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/06/29 01:51:47 UTC
(shardingsphere) branch master updated: Improve model-facing workflow guidance (#38946)
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 fbd3b8ea872 Improve model-facing workflow guidance (#38946)
fbd3b8ea872 is described below
commit fbd3b8ea87216fb80a07f55b62c1ca41a8dd2927
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Mon Jun 29 09:51:41 2026 +0800
Improve model-facing workflow guidance (#38946)
* Improve model-facing workflow guidance
- require confirmation before SQL side-effect execution
- expose metadata search truncation counts and narrowing actions
- add planning runtime metadata and completion targets
- refresh workflow recovery prompts and model contract baseline
* Improve model-facing workflow guidance
- require confirmation before SQL side-effect execution
- expose metadata search truncation counts and narrowing actions
- add planning runtime metadata and completion targets
- refresh workflow recovery prompts and model contract baseline
* Improve model-facing workflow guidance
- require confirmation before SQL side-effect execution
- expose metadata search truncation counts and narrowing actions
- add planning runtime metadata and completion targets
- refresh workflow recovery prompts and model contract baseline
* Improve model-facing workflow guidance
- require confirmation before SQL side-effect execution
- expose metadata search truncation counts and narrowing actions
- add planning runtime metadata and completion targets
- refresh workflow recovery prompts and model contract baseline
---
.codex/skills/review-pr/SKILL.md | 5 +++
.../prompt/MCPPromptSpecificationFactoryTest.java | 2 +-
.../handler/execute/ExecuteUpdateToolHandler.java | 10 ++++-
.../metadata/SearchMetadataToolHandler.java | 20 +++++++++-
.../metadata/SearchMetadataToolService.java | 10 ++++-
.../core/tool/response/MetadataSearchResult.java | 6 +++
.../core/workflow/WorkflowExecutionService.java | 18 +++++----
.../mcp-descriptors/mcp-descriptor-core.yaml | 40 +++++++++++++++++++
.../CoreToolDescriptorValidatorTest.java | 3 ++
.../capability/ServerCapabilitiesHandlerTest.java | 3 ++
.../execute/ExecuteUpdateToolHandlerTest.java | 18 ++++++---
.../metadata/SearchMetadataToolHandlerTest.java | 37 ++++++++++++++++++
.../metadata/SearchMetadataToolServiceTest.java | 21 ++++++++++
.../workflow/WorkflowExecutionServiceTest.java | 8 +++-
.../BroadcastToolDescriptorValidator.java | 3 +-
.../mcp-descriptors/mcp-descriptor-broadcast.yaml | 9 +++++
.../BroadcastToolDescriptorValidatorTest.java | 19 ++++++++-
.../ReadwriteSplittingToolDescriptorValidator.java | 3 +-
.../mcp-descriptor-readwrite-splitting.yaml | 10 +++++
...dwriteSplittingToolDescriptorValidatorTest.java | 8 +++-
.../descriptor/ShadowToolDescriptorValidator.java | 3 +-
.../mcp-descriptors/mcp-descriptor-shadow.yaml | 25 ++++++++++++
.../ShadowToolDescriptorValidatorTest.java | 10 +++--
.../ShardingToolDescriptorValidator.java | 3 +-
.../mcp-descriptors/mcp-descriptor-sharding.yaml | 45 ++++++++++++++++++++++
.../plan-sharding-rule-component-cleanup.md | 11 +++++-
.../prompts/plan-sharding-table-rule.md | 15 +++++++-
.../ShardingToolDescriptorValidatorTest.java | 16 +++++---
.../MCPModelFirstContractPayloadBuilder.java | 2 +-
.../mcp-descriptors/mcp-descriptor-support.yaml | 17 +++++++-
.../shardingsphere-mcp/prompts/recover-workflow.md | 4 +-
.../MCPModelFirstContractPayloadBuilderTest.java | 1 +
.../impl/ShardingSphereProxyEmbeddedContainer.java | 27 +++++++++++--
.../LLMMCPModelFacingToolResponseFormatter.java | 3 ++
.../AbstractProductionMySQLRuntimeE2ETest.java | 10 ++++-
.../HttpTransportBaselineContractE2ETest.java | 12 +++++-
.../ProxyEncryptWorkflowRuntimeTestSupport.java | 25 +++---------
.../model-contract/capabilities.yaml | 38 +++++++++++++-----
38 files changed, 445 insertions(+), 75 deletions(-)
diff --git a/.codex/skills/review-pr/SKILL.md b/.codex/skills/review-pr/SKILL.md
index c69b7b75f54..74c7f7365c6 100644
--- a/.codex/skills/review-pr/SKILL.md
+++ b/.codex/skills/review-pr/SKILL.md
@@ -56,6 +56,10 @@ Before applying the numbered review gates, enforce the public evidence boundary:
use `Review Result: Not Mergeable` with `Feedback Mode: Needs Discussion`.
5. Review only the latest PR code version, and use GitHub PR metadata plus `/pulls/{number}/files` as the authoritative scope boundary.
6. Use repository-declared formatting/style gates as the formatting authority.
+ For ShardingSphere, Spotless and Checkstyle are authoritative.
+ Do not run `git diff --check`, editor whitespace lint, or other generic whitespace diagnostics as routine review verification.
+ Use them only when repository workflows explicitly require them, the user asks for whitespace review, the review target is formatting rules, or whitespace has direct semantic impact.
+ Do not report Spotless-stable whitespace, including formatter-preserved blank-line indentation, as a blocker.
7. Treat substantive unrelated changes or substantive scope expansion as blockers; ignore non-behavioral import-only, whitespace-only, formatter-only, or IDE cleanup churn unless it hides behavior,
fails declared gates, touches broad unrelated areas, or violates explicit scope rules.
8. Before considering `Mergeable`, apply all triggered hard gates and specialized review gates, including semantic compatibility, counterexamples, blast-radius/shared-layer ownership,
@@ -185,6 +189,7 @@ Choose the feedback mode before writing the GitHub-facing review:
Record head SHA, base ref/SHA, merge-base, and whether the local file list matches GitHub.
- Do not base the result solely on CI, and do not wait for CI when static/code evidence is already sufficient.
- Use repository-declared style gates as authority. For ShardingSphere, Spotless and Checkstyle are authoritative.
+ Do not use `git diff --check` or other generic whitespace diagnostics as routine review verification unless the Mandatory Constraints exception applies.
## Non-Behavioral Churn Rule
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/prompt/MCPPromptSpecificationFactoryTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/prompt/MCPPromptSpecificationFactoryTest.java
index 37fe8d9ae42..ab478a4be2a 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/prompt/MCPPromptSpecificationFactoryTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/prompt/MCPPromptSpecificationFactoryTest.java
@@ -82,7 +82,7 @@ class MCPPromptSpecificationFactoryTest {
"- plan_id: plan-1",
"- failure_summary: metadata mismatch",
"1. Treat plan_id as a current-session handle only. Do not reuse it across MCP sessions.",
- "5. Preserve user-provided corrections when re-planning with database_gateway_plan_encrypt_rule or database_gateway_plan_mask_rule."));
+ "5. Preserve user-provided corrections when re-planning with the matching database_gateway_plan_* tool."));
}
@Test
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandler.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandler.java
index 461cbf313a4..8fda589efc0 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandler.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandler.java
@@ -54,6 +54,8 @@ public final class ExecuteUpdateToolHandler implements MCPToolHandler<MCPDatabas
private static final String PREVIEW_REVIEW_GUIDANCE = "Review normalized_sql and side_effect_scope before execution. "
+ "This preview is classification-only; it does not guarantee parsing, rule validation, algorithm initialization, affected rows, or runtime success.";
+ private static final String PREVIEW_CONFIRMATION_REASON = "Confirm that normalized_sql and side_effect_scope still match the intended side effect before execution.";
+
private static final String PREVIEW_EXECUTION_REASON = "Execute only after reviewing normalized_sql and side_effect_scope; preview did not validate runtime executability.";
@Override
@@ -121,10 +123,16 @@ public final class ExecuteUpdateToolHandler implements MCPToolHandler<MCPDatabas
result.put("suggested_arguments", suggestedArguments);
result.put(MCPPayloadFieldNames.RESOURCES_TO_READ, createResourcesToRead(toolArguments));
result.put("argument_provenance", createArgumentProvenance(suggestedArguments));
- result.put(MCPPayloadFieldNames.NEXT_ACTIONS, List.of(MCPNextActionUtils.callTool(TOOL_NAME, PREVIEW_EXECUTION_REASON, suggestedArguments)));
+ result.put(MCPPayloadFieldNames.NEXT_ACTIONS, createPreviewNextActions(suggestedArguments));
return new MCPMapResponse(result);
}
+ private List<Map<String, Object>> createPreviewNextActions(final Map<String, Object> suggestedArguments) {
+ return MCPNextActionUtils.ordered(
+ MCPNextActionUtils.askUser(PREVIEW_CONFIRMATION_REASON, List.of("execution_approved")),
+ MCPNextActionUtils.dependsOn(MCPNextActionUtils.callTool(TOOL_NAME, PREVIEW_EXECUTION_REASON, suggestedArguments), 1));
+ }
+
private String createReviewSummary(final ClassificationResult classificationResult) {
return String.format("Previewed %s statement with side-effect scope %s. It has not been executed.", classificationResult.getStatementType(),
String.join(", ", createSideEffectScope(classificationResult)));
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandler.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandler.java
index 0c073a2ee11..f17566f8ead 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandler.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandler.java
@@ -74,9 +74,14 @@ public final class SearchMetadataToolHandler implements MCPToolHandler<MCPDataba
}
private Map<String, Object> createSearchPayloadMetadata(final MCPDatabaseHandlerContext databaseContext, final MetadataSearchRequest request, final MetadataSearchResult searchResult) {
- Map<String, Object> result = new LinkedHashMap<>(4, 1F);
+ Map<String, Object> result = new LinkedHashMap<>(8, 1F);
result.put("search_context", searchResult.getSearchContext());
result.put("total_match_count", searchResult.getTotalMatchCount());
+ result.put("returned_count", searchResult.getReturnedCount());
+ result.put("truncated", searchResult.isTruncated());
+ if (searchResult.isTruncated()) {
+ result.put("large_result_guidance", createLargeResultGuidance(searchResult));
+ }
if (searchResult.getItems().isEmpty()) {
result.put("empty_state", createEmptyState(databaseContext, request));
result.put(MCPPayloadFieldNames.NEXT_ACTIONS, List.of(createEmptySearchNextAction(request)));
@@ -93,12 +98,25 @@ public final class SearchMetadataToolHandler implements MCPToolHandler<MCPDataba
return result;
}
+ private Map<String, Object> createLargeResultGuidance(final MetadataSearchResult searchResult) {
+ Map<String, Object> result = new LinkedHashMap<>(4, 1F);
+ result.put("state", "metadata_search_result_truncated");
+ result.put("threshold", searchResult.getLargeResultThreshold());
+ result.put("narrowing_arguments", List.of("database", "schema", "query", "object_types"));
+ result.put(MCPPayloadFieldNames.REASON, "Search matched more metadata objects than returned; narrow the search before reading specific resources.");
+ return result;
+ }
+
private List<Map<String, Object>> createResultNextActions(final MetadataSearchResult searchResult, final List<String> duplicatedNames) {
List<Map<String, Object>> result = new LinkedList<>();
if (isBroadSearchGuarded(searchResult)) {
result.add(MCPNextActionUtils.askUser("Blank cross-database metadata search listed databases only. Choose a database, query, or object type before searching deeper metadata.",
List.of("database", "query", "object_types")));
}
+ if (searchResult.isTruncated() && !isBroadSearchGuarded(searchResult)) {
+ result.add(MCPNextActionUtils.askUser("Metadata search results were truncated. Choose database, schema, query, or object type before reading specific resources.",
+ List.of("database", "schema", "query", "object_types")));
+ }
if (!duplicatedNames.isEmpty()) {
result.add(MCPNextActionUtils.askUser("Multiple metadata hits share the same name. Ask the user to choose database, schema, or object type before using a specific resource.",
List.of("database", "schema", "object_types")));
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolService.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolService.java
index a51581e335c..9543fe9e90a 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolService.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolService.java
@@ -39,6 +39,8 @@ import java.util.Set;
*/
public final class SearchMetadataToolService {
+ private static final int LARGE_RESULT_THRESHOLD = 100;
+
private static final Map<String, Integer> OBJECT_TYPE_ORDERS = Map.of(
"database", 0, "schema", 1, "storage_unit", 2, "table", 3, "view", 4, "column", 5, "index", 6, "sequence", 7);
@@ -82,7 +84,13 @@ public final class SearchMetadataToolService {
final Set<SupportedMCPMetadataObjectType> searchObjectTypes, final boolean broadSearchGuarded) {
List<MetadataSearchHit> filteredItems = matcher.filterByQuery(metadataItems, request.getQuery());
filteredItems.sort(this::compareSearchHits);
- return new MetadataSearchResult(filteredItems, createSearchContext(request, searchObjectTypes, broadSearchGuarded), filteredItems.size());
+ List<MetadataSearchHit> returnedItems = capSearchResult(filteredItems);
+ return new MetadataSearchResult(returnedItems, createSearchContext(request, searchObjectTypes, broadSearchGuarded), filteredItems.size(), returnedItems.size(),
+ returnedItems.size() < filteredItems.size(), LARGE_RESULT_THRESHOLD);
+ }
+
+ private List<MetadataSearchHit> capSearchResult(final List<MetadataSearchHit> items) {
+ return items.size() <= LARGE_RESULT_THRESHOLD ? items : items.subList(0, LARGE_RESULT_THRESHOLD);
}
private Map<String, Object> createSearchContext(final MetadataSearchRequest request, final Set<SupportedMCPMetadataObjectType> searchObjectTypes, final boolean broadSearchGuarded) {
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/response/MetadataSearchResult.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/response/MetadataSearchResult.java
index 74983c9b3df..2c2c3554e04 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/response/MetadataSearchResult.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/response/MetadataSearchResult.java
@@ -35,4 +35,10 @@ public final class MetadataSearchResult {
private final Map<String, Object> searchContext;
private final int totalMatchCount;
+
+ private final int returnedCount;
+
+ private final boolean truncated;
+
+ private final int largeResultThreshold;
}
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionService.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionService.java
index 30f4b622eaf..5ef49a19e08 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionService.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionService.java
@@ -283,18 +283,20 @@ public final class WorkflowExecutionService {
return result;
}
- private Map<String, Object> createPreviewNextAction(final WorkflowContextSnapshot snapshot) {
- String executionMode = resolveApplyExecutionMode(snapshot);
- return EXECUTION_MODE_MANUAL_ONLY.equals(executionMode)
- ? MCPNextActionUtils.callTool("database_gateway_apply_workflow", createPreviewNextActionReason(executionMode), createExecutionArguments(snapshot, executionMode))
- : MCPNextActionUtils.askUser(createPreviewNextActionReason(executionMode), List.of("approved_steps"));
- }
-
private List<Map<String, Object>> createPreviewNextActions(final WorkflowContextSnapshot snapshot, final List<Map<String, Object>> previewArtifacts) {
if (previewArtifacts.isEmpty()) {
return MCPNextActionUtils.ordered(MCPNextActionUtils.stop("Preview has no artifacts to approve."));
}
- return MCPNextActionUtils.ordered(createPreviewNextAction(snapshot));
+ String executionMode = resolveApplyExecutionMode(snapshot);
+ if (EXECUTION_MODE_MANUAL_ONLY.equals(executionMode)) {
+ return MCPNextActionUtils
+ .ordered(MCPNextActionUtils.callTool("database_gateway_apply_workflow", createPreviewNextActionReason(executionMode), createExecutionArguments(snapshot, executionMode)));
+ }
+ return MCPNextActionUtils.ordered(
+ MCPNextActionUtils.askUser(createPreviewNextActionReason(executionMode), List.of("approved_steps")),
+ MCPNextActionUtils.dependsOn(MCPNextActionUtils.callTool("database_gateway_apply_workflow",
+ "Apply reviewed workflow artifacts after merging approved_steps from action 1 into the arguments.",
+ createExecutionArguments(snapshot, executionMode)), 1));
}
private String createPreviewNextActionReason(final String executionMode) {
diff --git a/mcp/core/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-core.yaml b/mcp/core/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-core.yaml
index dcc3050e68f..7bbe10932ec 100644
--- a/mcp/core/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-core.yaml
+++ b/mcp/core/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-core.yaml
@@ -858,6 +858,28 @@ tools:
total_match_count:
type: integer
description: "Total matched metadata objects for this search scope."
+ returned_count:
+ type: integer
+ description: "Number of matched metadata objects returned after search result capping."
+ truncated:
+ type: boolean
+ description: "Whether search hits were capped by the large-result threshold."
+ large_result_guidance:
+ type: object
+ description: "Structured narrowing guidance when matched metadata results are truncated."
+ properties:
+ state:
+ type: string
+ description: "Large-result guidance state."
+ threshold:
+ type: integer
+ description: "Maximum number of metadata hits returned before truncation."
+ narrowing_arguments:
+ type: array
+ description: "Public database_gateway_search_metadata arguments the model can set to narrow the result."
+ reason:
+ type: string
+ description: "Why the model should narrow the search."
empty_state:
type: object
description: "Structured empty state when no metadata hits were returned."
@@ -907,9 +929,15 @@ tools:
reason:
type: string
description: "Why the model should take this action."
+ question:
+ type: string
+ description: "Question to ask the user when type is ask_user."
required_inputs:
type: array
description: "User inputs needed before continuing."
+ depends_on:
+ type: array
+ description: "Action order values that must complete before this action."
examples:
- response_mode: search
items:
@@ -1380,6 +1408,9 @@ tools:
reason:
type: string
description: "Why the model should take this action."
+ question:
+ type: string
+ description: "Question to ask the user when type is ask_user."
required_inputs:
type: array
description: "User inputs needed before continuing."
@@ -1405,11 +1436,20 @@ tools:
execution_mode: execute
next_actions:
- order: 1
+ type: ask_user
+ title: Ask user
+ question: Confirm that normalized_sql and side_effect_scope still match the intended side effect before execution.
+ required_inputs:
+ - execution_approved
+ reason: Confirm that normalized_sql and side_effect_scope still match the intended side effect before execution.
+ - order: 2
type: tool_call
title: Call database_gateway_execute_update
tool_name: database_gateway_execute_update
arguments:
execution_mode: execute
+ depends_on:
+ - 1
reason: Execute only after reviewing normalized_sql and side_effect_scope; preview did not validate runtime executability.
annotations:
title: Execute Update SQL
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/descriptor/CoreToolDescriptorValidatorTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/descriptor/CoreToolDescriptorValidatorTest.java
index 6469918bcc1..b1b54cf103a 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/descriptor/CoreToolDescriptorValidatorTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/descriptor/CoreToolDescriptorValidatorTest.java
@@ -48,6 +48,9 @@ class CoreToolDescriptorValidatorTest {
assertTrue(getInputProperties(descriptor).containsKey("query"));
assertTrue(getOutputProperties(descriptor).containsKey("search_context"));
assertTrue(getOutputProperties(descriptor).containsKey("total_match_count"));
+ assertTrue(getOutputProperties(descriptor).containsKey("returned_count"));
+ assertTrue(getOutputProperties(descriptor).containsKey("truncated"));
+ assertTrue(getOutputProperties(descriptor).containsKey("large_result_guidance"));
}
@Test
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/capability/ServerCapabilitiesHandlerTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/capability/ServerCapabilitiesHandlerTest.java
index 5ce1bf4b841..08231b6b954 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/capability/ServerCapabilitiesHandlerTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/capability/ServerCapabilitiesHandlerTest.java
@@ -240,6 +240,9 @@ class ServerCapabilitiesHandlerTest {
Map<?, ?> searchMetadataTool = findTool(capabilities, "database_gateway_search_metadata");
Map<?, ?> searchMetadataOutputProperties = (Map<?, ?>) ((Map<?, ?>) searchMetadataTool.get("outputSchema")).get("properties");
assertTrue(searchMetadataOutputProperties.containsKey("total_match_count"));
+ assertTrue(searchMetadataOutputProperties.containsKey("returned_count"));
+ assertTrue(searchMetadataOutputProperties.containsKey("truncated"));
+ assertTrue(searchMetadataOutputProperties.containsKey("large_result_guidance"));
Map<?, ?> objectTypesSchema = findInputSchema(searchMetadataTool, "object_types");
assertTrue(((List<?>) ((Map<?, ?>) objectTypesSchema.get("items")).get("enum")).containsAll(List.of("database", "schema", "table", "view", "column", "index", "sequence")));
Map<?, ?> validateRuntimeDatabaseTool = findTool(capabilities, "database_gateway_validate_runtime_database");
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandlerTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandlerTest.java
index 0fa27b60b4c..eced0f748b7 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandlerTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandlerTest.java
@@ -121,13 +121,19 @@ class ExecuteUpdateToolHandlerTest {
assertThat(((Map<?, ?>) actual.toPayload().get("argument_provenance")).get("sql"), is("server_generated"));
assertThat(((Map<?, ?>) actual.toPayload().get("argument_provenance")).get("execution_mode"), is("server_defaulted"));
List<?> actualNextActions = (List<?>) actual.toPayload().get("next_actions");
- assertThat(actualNextActions.size(), is(1));
- assertThat(((Map<?, ?>) actualNextActions.getFirst()).get("type"), is("tool_call"));
- assertThat(((Map<?, ?>) actualNextActions.getFirst()).get("order"), is(1));
- assertThat(((Map<?, ?>) actualNextActions.getFirst()).get("tool_name"), is("database_gateway_execute_update"));
- assertThat(((Map<?, ?>) actualNextActions.getFirst()).get("reason"),
+ assertThat(actualNextActions.size(), is(2));
+ Map<?, ?> actualAskUserAction = (Map<?, ?>) actualNextActions.getFirst();
+ assertThat(actualAskUserAction.get("type"), is("ask_user"));
+ assertThat(actualAskUserAction.get("order"), is(1));
+ assertThat(actualAskUserAction.get("required_inputs"), is(List.of("execution_approved")));
+ Map<?, ?> actualToolCallAction = (Map<?, ?>) actualNextActions.get(1);
+ assertThat(actualToolCallAction.get("type"), is("tool_call"));
+ assertThat(actualToolCallAction.get("order"), is(2));
+ assertThat(actualToolCallAction.get("tool_name"), is("database_gateway_execute_update"));
+ assertThat(actualToolCallAction.get("depends_on"), is(List.of(1)));
+ assertThat(actualToolCallAction.get("reason"),
is("Execute only after reviewing normalized_sql and side_effect_scope; preview did not validate runtime executability."));
- assertThat(((Map<?, ?>) ((Map<?, ?>) actualNextActions.getFirst()).get("arguments")).get("execution_mode"), is("execute"));
+ assertThat(((Map<?, ?>) actualToolCallAction.get("arguments")).get("execution_mode"), is("execute"));
assertThat(((Map<?, ?>) ((List<?>) actual.toPayload().get("resources_to_read")).getFirst()).get("uri"), is("shardingsphere://databases/logic_db/capabilities"));
assertFalse(actual.toPayload().containsKey("ask_user_when_uncertain"));
verifyNoInteractions(executionFacade);
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandlerTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandlerTest.java
index 4d88b96c7c8..c6cede663a6 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandlerTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolHandlerTest.java
@@ -71,6 +71,9 @@ class SearchMetadataToolHandlerTest {
assertTrue(actualItemProperties.containsKey("matched_value"));
assertTrue(actualProperties.containsKey("search_context"));
assertTrue(actualProperties.containsKey("total_match_count"));
+ assertTrue(actualProperties.containsKey("returned_count"));
+ assertTrue(actualProperties.containsKey("truncated"));
+ assertTrue(actualProperties.containsKey("large_result_guidance"));
assertTrue(actualProperties.containsKey("empty_state"));
assertTrue(actualProperties.containsKey("ambiguity_state"));
assertTrue(actualProperties.containsKey("next_actions"));
@@ -86,6 +89,8 @@ class SearchMetadataToolHandlerTest {
assertThat(actual, isA(MCPItemsResponse.class));
assertThat(((List<?>) actualPayload.get("items")).size(), is(1));
assertThat(actualPayload.get("total_match_count"), is(1));
+ assertThat(actualPayload.get("returned_count"), is(1));
+ assertFalse((Boolean) actualPayload.get("truncated"));
assertFalse(actualPayload.containsKey("next_page_token"));
assertFalse((Boolean) actualPayload.get("has_more"));
assertThat(actualPayload.get("continuation_mode"), is("none"));
@@ -145,11 +150,35 @@ class SearchMetadataToolHandlerTest {
assertThat(actual, isA(MCPItemsResponse.class));
assertThat(actualNames.size(), is(9));
assertThat(actualPayload.get("total_match_count"), is(9));
+ assertThat(actualPayload.get("returned_count"), is(9));
+ assertFalse((Boolean) actualPayload.get("truncated"));
assertTrue(actualNames.contains("logic_db"));
assertTrue(actualNames.contains("order_idx"));
}
}
+ @Test
+ void assertHandleSearchMetadataWithLargeResultGuidance() {
+ try (MCPRequestScope requestContext = new MCPRequestScope(createSearchRuntimeContext(createLargeDatabaseMetadata()))) {
+ MCPResponse actual = new SearchMetadataToolHandler().handle(requestContext, new MCPToolCall("session-1",
+ Map.of("database", "large_db", "object_types", List.of(SupportedMCPMetadataObjectType.TABLE.name()))));
+ Map<String, Object> actualPayload = actual.toPayload();
+ assertThat(((List<?>) actualPayload.get("items")).size(), is(100));
+ assertThat(actualPayload.get("total_match_count"), is(101));
+ assertThat(actualPayload.get("returned_count"), is(100));
+ assertTrue((Boolean) actualPayload.get("truncated"));
+ Map<?, ?> actualLargeResultGuidance = (Map<?, ?>) actualPayload.get("large_result_guidance");
+ assertThat(actualLargeResultGuidance.get("state"), is("metadata_search_result_truncated"));
+ assertThat(actualLargeResultGuidance.get("threshold"), is(100));
+ assertThat(actualLargeResultGuidance.get("narrowing_arguments"), is(List.of("database", "schema", "query", "object_types")));
+ List<?> actualNextActions = (List<?>) actualPayload.get("next_actions");
+ assertThat(actualNextActions.size(), is(1));
+ Map<?, ?> actualNextAction = (Map<?, ?>) actualNextActions.getFirst();
+ assertThat(actualNextAction.get("type"), is("ask_user"));
+ assertThat(actualNextAction.get("required_inputs"), is(List.of("database", "schema", "query", "object_types")));
+ }
+ }
+
@Test
void assertHandleSearchMetadataWithBlankAllDatabaseGuard() {
try (MCPRequestScope requestContext = new MCPRequestScope(createSearchRuntimeContext())) {
@@ -299,6 +328,14 @@ class SearchMetadataToolHandlerTest {
return List.of(createDatabaseMetadata("bar_db", "orders"), createDatabaseMetadata("baz_db", "orders"), createDatabaseMetadata("foo_db", "orders_archive"));
}
+ private List<MCPDatabaseMetadata> createLargeDatabaseMetadata() {
+ List<MCPTableMetadata> tables = new LinkedList<>();
+ for (int index = 0; index < 101; index++) {
+ tables.add(new MCPTableMetadata("large_db", "public", "table_" + index, List.of(), List.of()));
+ }
+ return List.of(new MCPDatabaseMetadata("large_db", "MySQL", "", List.of(new MCPSchemaMetadata("large_db", "public", tables, List.of(), List.of()))));
+ }
+
private MCPDatabaseMetadata createDatabaseMetadata(final String databaseName, final String tableName) {
return new MCPDatabaseMetadata(databaseName, "MySQL", "", List.of(
new MCPSchemaMetadata(databaseName, "public", List.of(new MCPTableMetadata(databaseName, "public", tableName, List.of(), List.of())), List.of(), List.of())));
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolServiceTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolServiceTest.java
index 3d3916c306f..0b31508318a 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolServiceTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataToolServiceTest.java
@@ -86,12 +86,25 @@ class SearchMetadataToolServiceTest {
MetadataSearchResult actual = execute(createDatabaseMetadata(), new MetadataSearchRequest("", "", "", Set.of()));
assertThat(actual.getItems().size(), is(4));
assertThat(actual.getTotalMatchCount(), is(4));
+ assertThat(actual.getReturnedCount(), is(4));
+ assertFalse(actual.isTruncated());
assertThat(actual.getSearchContext().get("object_types"), is(List.of("database")));
assertTrue((Boolean) actual.getSearchContext().get("broad_search_guarded"));
assertThat(actual.getSearchContext().get("recommended_narrowing_arguments"), is(List.of("database", "query", "object_types")));
assertFalse(actual.getItems().stream().map(MetadataSearchHit::getName).collect(Collectors.toSet()).contains("orders"));
}
+ @Test
+ void assertExecuteSearchCapsLargeResult() {
+ MetadataSearchResult actual = execute(createLargeDatabaseMetadata(),
+ new MetadataSearchRequest("large_db", "", "", Set.of(SupportedMCPMetadataObjectType.TABLE)));
+ assertThat(actual.getItems().size(), is(100));
+ assertThat(actual.getTotalMatchCount(), is(101));
+ assertThat(actual.getReturnedCount(), is(100));
+ assertTrue(actual.isTruncated());
+ assertThat(actual.getLargeResultThreshold(), is(100));
+ }
+
@Test
void assertExecuteSearchWithCompleteResult() {
Set<SupportedMCPMetadataObjectType> objectTypes = new LinkedHashSet<>(List.of(SupportedMCPMetadataObjectType.TABLE, SupportedMCPMetadataObjectType.VIEW));
@@ -342,6 +355,14 @@ class SearchMetadataToolServiceTest {
List.of(new MCPSchemaMetadata("schema_less_db", "", List.of(new MCPTableMetadata("schema_less_db", "", "schema_less_orders", List.of(), List.of())), List.of(), List.of()))));
}
+ private List<MCPDatabaseMetadata> createLargeDatabaseMetadata() {
+ List<MCPTableMetadata> tables = new LinkedList<>();
+ for (int index = 0; index < 101; index++) {
+ tables.add(new MCPTableMetadata("large_db", "public", "table_" + index, List.of(), List.of()));
+ }
+ return List.of(new MCPDatabaseMetadata("large_db", "MySQL", "", List.of(new MCPSchemaMetadata("large_db", "public", tables, List.of(), List.of()))));
+ }
+
private List<MCPDatabaseMetadata> createDatabaseMetadataWithUnsafeUriName() {
return List.of(new MCPDatabaseMetadata("逻辑 库", "MySQL", "",
List.of(new MCPSchemaMetadata("逻辑 库", "public/main",
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionServiceTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionServiceTest.java
index 95babc9c8b2..cab4a8820f8 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionServiceTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionServiceTest.java
@@ -246,11 +246,15 @@ class WorkflowExecutionServiceTest {
assertThat(actualReviewFocus.get("approval_values"), is(List.of("ddl", "rule_distsql")));
assertThat(actualResponse.get("review_summary"), is("Previewed 2 workflow artifacts with side-effect scope physical-structure, rule-metadata. Nothing has been applied."));
List<?> actualNextActions = (List<?>) actualResponse.get("next_actions");
- assertThat(actualNextActions.size(), is(1));
+ assertThat(actualNextActions.size(), is(2));
Map<?, ?> actualNextAction = (Map<?, ?>) actualNextActions.getFirst();
assertThat(actualNextAction.get("type"), is("ask_user"));
assertThat(actualNextAction.get("required_inputs"), is(List.of("approved_steps")));
- assertFalse(actualNextAction.containsKey("depends_on"));
+ Map<?, ?> actualToolCallAction = (Map<?, ?>) actualNextActions.get(1);
+ assertThat(actualToolCallAction.get("type"), is("tool_call"));
+ assertThat(actualToolCallAction.get("tool_name"), is("database_gateway_apply_workflow"));
+ assertThat(actualToolCallAction.get("depends_on"), is(List.of(1)));
+ assertThat(actualToolCallAction.get("reason"), is("Apply reviewed workflow artifacts after merging approved_steps from action 1 into the arguments."));
assertThat(((Map<?, ?>) actualResponse.get("argument_provenance")).get("plan_id"), is("server_generated"));
assertThat(((Map<?, ?>) actualResponse.get("argument_provenance")).get("execution_mode"), is("server_defaulted"));
assertThat(workflowSessionContext.getRequired("plan-1").getStatus(), is("previewed"));
diff --git a/mcp/features/broadcast/src/main/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidator.java b/mcp/features/broadcast/src/main/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidator.java
index a4c2b4e797d..8f1a8efc81b 100644
--- a/mcp/features/broadcast/src/main/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidator.java
+++ b/mcp/features/broadcast/src/main/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidator.java
@@ -39,7 +39,8 @@ public final class BroadcastToolDescriptorValidator implements MCPToolDescriptor
"distsql_artifacts", MCPPayloadFieldNames.RESOURCES_TO_READ, MCPPayloadFieldNames.NEXT_ACTIONS);
private static final List<String> REQUIRED_META_FIELDS = List.of(
- "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
@Override
public boolean supports(final MCPToolDescriptor toolDescriptor) {
diff --git a/mcp/features/broadcast/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-broadcast.yaml b/mcp/features/broadcast/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-broadcast.yaml
index 29344b67a04..4ef0313b9d1 100644
--- a/mcp/features/broadcast/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-broadcast.yaml
+++ b/mcp/features/broadcast/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-broadcast.yaml
@@ -114,6 +114,13 @@ prompts:
- "Ask when database or logical broadcast table names are unclear."
- "Ask before applying generated broadcast rule DistSQL that changes runtime state."
+completionTargets:
+ - referenceType: prompt
+ reference: plan_broadcast_rule
+ arguments:
+ - database
+ maxValues: 50
+
resourceNavigation:
- from: shardingsphere://features/broadcast/databases/{database}/rules
to: database_gateway_plan_broadcast_rule
@@ -350,6 +357,8 @@ tools:
destructiveHint: false
idempotentHint: false
openWorldHint: false
+ runtime:
+ workflowRole: plan
meta:
org.apache.shardingsphere/workflow-kind: broadcast.rule
org.apache.shardingsphere/artifact-categories:
diff --git a/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidatorTest.java b/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidatorTest.java
index 9a36c5c5a08..f7601e66c94 100644
--- a/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidatorTest.java
+++ b/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/descriptor/BroadcastToolDescriptorValidatorTest.java
@@ -20,6 +20,7 @@ package org.apache.shardingsphere.mcp.feature.broadcast.descriptor;
import org.apache.shardingsphere.mcp.api.prompt.descriptor.MCPPromptDescriptor;
import org.apache.shardingsphere.mcp.api.tool.descriptor.MCPToolDescriptor;
import org.apache.shardingsphere.mcp.feature.broadcast.BroadcastFeatureDefinition;
+import org.apache.shardingsphere.mcp.support.descriptor.MCPCompletionTargetDescriptor;
import org.apache.shardingsphere.mcp.support.descriptor.MCPDescriptorCatalogIndex;
import org.apache.shardingsphere.mcp.support.descriptor.MCPPromptTemplateLoader;
import org.apache.shardingsphere.mcp.support.descriptor.MCPShardingSphereMetadataKeys;
@@ -92,6 +93,15 @@ class BroadcastToolDescriptorValidatorTest {
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/workflow-kind"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/related-resource-uris"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/follow-up-tools"));
+ assertTrue(MCPDescriptorCatalogIndex.findToolRuntimeDescriptor(BroadcastFeatureDefinition.PLAN_TOOL_NAME)
+ .filter(optional -> "plan".equals(optional.getWorkflowRole())).isPresent());
+ }
+
+ @Test
+ void assertExposeCompletionTargets() {
+ MCPCompletionTargetDescriptor actual = findCompletionTarget("prompt", BroadcastFeatureDefinition.PLAN_PROMPT_NAME);
+ assertThat(actual.getArguments(), is(List.of("database")));
+ assertThat(actual.getMaxValues(), is(50));
}
@Test
@@ -146,13 +156,20 @@ class BroadcastToolDescriptorValidatorTest {
}
private static Stream<String> requiredMetadataFields() {
- return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
}
private MCPPromptDescriptor findPrompt(final String promptName) {
return MCPDescriptorCatalogIndex.getPromptDescriptors().stream().filter(each -> promptName.equals(each.getName())).findFirst().orElseThrow();
}
+ private MCPCompletionTargetDescriptor findCompletionTarget(final String referenceType, final String reference) {
+ return MCPDescriptorCatalogIndex.getCompletionTargetDescriptors().stream()
+ .filter(each -> referenceType.equals(each.getReferenceType()) && reference.equals(each.getReference()))
+ .findFirst().orElseThrow();
+ }
+
private String readResource(final String resourceName) throws IOException {
try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName)) {
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
diff --git a/mcp/features/readwrite-splitting/src/main/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidator.java b/mcp/features/readwrite-splitting/src/main/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidator.java
index 64c5016cfae..6ea221cf526 100644
--- a/mcp/features/readwrite-splitting/src/main/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidator.java
+++ b/mcp/features/readwrite-splitting/src/main/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidator.java
@@ -39,7 +39,8 @@ public final class ReadwriteSplittingToolDescriptorValidator implements MCPToolD
"distsql_artifacts", MCPPayloadFieldNames.RESOURCES_TO_READ, MCPPayloadFieldNames.NEXT_ACTIONS);
private static final List<String> REQUIRED_META_FIELDS = List.of(
- "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
@Override
public boolean supports(final MCPToolDescriptor toolDescriptor) {
diff --git a/mcp/features/readwrite-splitting/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-readwrite-splitting.yaml b/mcp/features/readwrite-splitting/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-readwrite-splitting.yaml
index 3b3f4b4fdaf..1cbee790e3b 100644
--- a/mcp/features/readwrite-splitting/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-readwrite-splitting.yaml
+++ b/mcp/features/readwrite-splitting/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-readwrite-splitting.yaml
@@ -220,8 +220,14 @@ completionTargets:
- referenceType: prompt
reference: plan_readwrite_splitting_rule
arguments:
+ - database
- load_balancer_type
maxValues: 50
+ - referenceType: prompt
+ reference: plan_readwrite_splitting_status
+ arguments:
+ - database
+ maxValues: 50
resourceNavigation:
- from: shardingsphere://features/readwrite-splitting/databases/{database}/rules
to: database_gateway_plan_readwrite_splitting_rule
@@ -526,6 +532,8 @@ tools:
destructiveHint: false
idempotentHint: false
openWorldHint: false
+ runtime:
+ workflowRole: plan
meta:
org.apache.shardingsphere/workflow-kind: readwrite.rule
org.apache.shardingsphere/artifact-categories:
@@ -640,6 +648,8 @@ tools:
destructiveHint: false
idempotentHint: false
openWorldHint: false
+ runtime:
+ workflowRole: plan
meta:
org.apache.shardingsphere/workflow-kind: readwrite.status
org.apache.shardingsphere/artifact-categories:
diff --git a/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidatorTest.java b/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidatorTest.java
index 28a2df78430..c2cf46c35fa 100644
--- a/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidatorTest.java
+++ b/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/descriptor/ReadwriteSplittingToolDescriptorValidatorTest.java
@@ -55,8 +55,10 @@ class ReadwriteSplittingToolDescriptorValidatorTest {
@Test
void assertExposeCompletionTargets() {
MCPCompletionTargetDescriptor promptCompletionTarget = findCompletionTarget("prompt", ReadwriteSplittingFeatureDefinition.PLAN_RULE_PROMPT_NAME);
- assertThat(promptCompletionTarget.getArguments(), is(List.of(ReadwriteSplittingFeatureDefinition.LOAD_BALANCER_TYPE_FIELD)));
+ assertThat(promptCompletionTarget.getArguments(), is(List.of("database", ReadwriteSplittingFeatureDefinition.LOAD_BALANCER_TYPE_FIELD)));
assertThat(promptCompletionTarget.getMaxValues(), is(50));
+ MCPCompletionTargetDescriptor statusPromptCompletionTarget = findCompletionTarget("prompt", ReadwriteSplittingFeatureDefinition.PLAN_STATUS_PROMPT_NAME);
+ assertThat(statusPromptCompletionTarget.getArguments(), is(List.of("database")));
assertFalse(hasCompletionTarget("resource", ReadwriteSplittingFeatureDefinition.LOAD_BALANCE_ALGORITHM_PLUGINS_RESOURCE_URI));
}
@@ -120,6 +122,7 @@ class ReadwriteSplittingToolDescriptorValidatorTest {
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/workflow-kind"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/related-resource-uris"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/follow-up-tools"));
+ assertTrue(MCPDescriptorCatalogIndex.findToolRuntimeDescriptor(each).filter(optional -> "plan".equals(optional.getWorkflowRole())).isPresent());
assertFalse(String.valueOf(descriptor.getOutputSchema()).contains("manual_artifact_package"));
}
}
@@ -192,7 +195,8 @@ class ReadwriteSplittingToolDescriptorValidatorTest {
}
private static Stream<String> requiredMetadataFields() {
- return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
}
private MCPPromptDescriptor findPrompt(final String promptName) {
diff --git a/mcp/features/shadow/src/main/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidator.java b/mcp/features/shadow/src/main/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidator.java
index 1428dc71198..2e4c4d5e5fa 100644
--- a/mcp/features/shadow/src/main/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidator.java
+++ b/mcp/features/shadow/src/main/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidator.java
@@ -39,7 +39,8 @@ public final class ShadowToolDescriptorValidator implements MCPToolDescriptorVal
"distsql_artifacts", MCPPayloadFieldNames.RESOURCES_TO_READ, MCPPayloadFieldNames.NEXT_ACTIONS);
private static final List<String> REQUIRED_META_FIELDS = List.of(
- "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
@Override
public boolean supports(final MCPToolDescriptor toolDescriptor) {
diff --git a/mcp/features/shadow/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-shadow.yaml b/mcp/features/shadow/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-shadow.yaml
index f48f1199f85..8b2c102f9e8 100644
--- a/mcp/features/shadow/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-shadow.yaml
+++ b/mcp/features/shadow/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-shadow.yaml
@@ -289,13 +289,20 @@ completionTargets:
- referenceType: prompt
reference: plan_shadow_rule
arguments:
+ - database
- algorithm_type
maxValues: 50
- referenceType: prompt
reference: plan_default_shadow_algorithm
arguments:
+ - database
- algorithm_type
maxValues: 50
+ - referenceType: prompt
+ reference: plan_shadow_algorithm_cleanup
+ arguments:
+ - database
+ maxValues: 50
resourceNavigation:
- from: shardingsphere://features/shadow/databases/{database}/rules
to: database_gateway_plan_shadow_rule
@@ -586,8 +593,14 @@ tools:
idempotentHint: false
openWorldHint: false
readOnlyHint: false
+ runtime:
+ workflowRole: plan
meta:
org.apache.shardingsphere/workflow-kind: shadow.rule
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/shadow/databases/{database}/rules
- shardingsphere://features/shadow/databases/{database}/table-rules
@@ -659,8 +672,14 @@ tools:
idempotentHint: false
openWorldHint: false
readOnlyHint: false
+ runtime:
+ workflowRole: plan
meta:
org.apache.shardingsphere/workflow-kind: shadow.default
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/shadow/databases/{database}/default-algorithm
- shardingsphere://features/shadow/databases/{database}/algorithms
@@ -722,8 +741,14 @@ tools:
idempotentHint: false
openWorldHint: false
readOnlyHint: false
+ runtime:
+ workflowRole: plan
meta:
org.apache.shardingsphere/workflow-kind: shadow.cleanup
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/shadow/databases/{database}/algorithms
- shardingsphere://features/shadow/databases/{database}/table-rules
diff --git a/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidatorTest.java b/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidatorTest.java
index ab1d28165ca..84e6d72c717 100644
--- a/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidatorTest.java
+++ b/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/descriptor/ShadowToolDescriptorValidatorTest.java
@@ -53,9 +53,11 @@ class ShadowToolDescriptorValidatorTest {
@Test
void assertExposeCompletionTargets() {
MCPCompletionTargetDescriptor rulePromptCompletionTarget = findCompletionTarget("prompt", ShadowFeatureDefinition.PLAN_RULE_PROMPT_NAME);
- assertThat(rulePromptCompletionTarget.getArguments(), is(List.of(ShadowFeatureDefinition.ALGORITHM_TYPE_FIELD)));
+ assertThat(rulePromptCompletionTarget.getArguments(), is(List.of("database", ShadowFeatureDefinition.ALGORITHM_TYPE_FIELD)));
MCPCompletionTargetDescriptor defaultPromptCompletionTarget = findCompletionTarget("prompt", ShadowFeatureDefinition.PLAN_DEFAULT_ALGORITHM_PROMPT_NAME);
- assertThat(defaultPromptCompletionTarget.getArguments(), is(List.of(ShadowFeatureDefinition.ALGORITHM_TYPE_FIELD)));
+ assertThat(defaultPromptCompletionTarget.getArguments(), is(List.of("database", ShadowFeatureDefinition.ALGORITHM_TYPE_FIELD)));
+ MCPCompletionTargetDescriptor cleanupPromptCompletionTarget = findCompletionTarget("prompt", ShadowFeatureDefinition.PLAN_ALGORITHM_CLEANUP_PROMPT_NAME);
+ assertThat(cleanupPromptCompletionTarget.getArguments(), is(List.of("database")));
assertFalse(hasCompletionTarget("resource", ShadowFeatureDefinition.ALGORITHM_PLUGINS_RESOURCE_URI));
}
@@ -94,6 +96,7 @@ class ShadowToolDescriptorValidatorTest {
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/workflow-kind"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/related-resource-uris"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/follow-up-tools"));
+ assertTrue(MCPDescriptorCatalogIndex.findToolRuntimeDescriptor(each).filter(optional -> "plan".equals(optional.getWorkflowRole())).isPresent());
}
}
@@ -146,7 +149,8 @@ class ShadowToolDescriptorValidatorTest {
}
private static Stream<String> requiredMetadataFields() {
- return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
}
private String readResource(final String resourceName) throws IOException {
diff --git a/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidator.java b/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidator.java
index aa91f760c4a..9b2f3bf3272 100644
--- a/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidator.java
+++ b/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidator.java
@@ -39,7 +39,8 @@ public final class ShardingToolDescriptorValidator implements MCPToolDescriptorV
"distsql_artifacts", MCPPayloadFieldNames.RESOURCES_TO_READ, MCPPayloadFieldNames.NEXT_ACTIONS);
private static final List<String> REQUIRED_META_FIELDS = List.of(
- "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ "org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
@Override
public boolean supports(final MCPToolDescriptor toolDescriptor) {
diff --git a/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-sharding.yaml b/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-sharding.yaml
index 8a5bb96aac9..221edec6c8e 100644
--- a/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-sharding.yaml
+++ b/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-sharding.yaml
@@ -528,23 +528,37 @@ completionTargets:
- referenceType: prompt
reference: plan_sharding_table_rule
arguments:
+ - database
- algorithm_type
maxValues: 50
+ - referenceType: prompt
+ reference: plan_sharding_table_reference_rule
+ arguments:
+ - database
+ maxValues: 50
- referenceType: prompt
reference: plan_sharding_default_strategy
arguments:
+ - database
- algorithm_type
maxValues: 50
- referenceType: prompt
reference: plan_sharding_key_generator
arguments:
+ - database
- key_generator_type
maxValues: 50
- referenceType: prompt
reference: plan_sharding_key_generate_strategy
arguments:
+ - database
- key_generator_type
maxValues: 50
+ - referenceType: prompt
+ reference: plan_sharding_rule_component_cleanup
+ arguments:
+ - database
+ maxValues: 50
resourceNavigation:
- from: shardingsphere://features/sharding/algorithm-plugins
to: database_gateway_plan_sharding_table_rule
@@ -839,8 +853,14 @@ tools:
idempotentHint: false
openWorldHint: false
readOnlyHint: false
+ runtime: &planningRuntime
+ workflowRole: plan
meta:
org.apache.shardingsphere/workflow-kind: sharding.table.rule
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/sharding/algorithm-plugins
- shardingsphere://features/sharding/key-generate-algorithm-plugins
@@ -869,8 +889,13 @@ tools:
additionalProperties: false
outputSchema: *workflowPlanOutputSchema
annotations: *planningAnnotations
+ runtime: *planningRuntime
meta:
org.apache.shardingsphere/workflow-kind: sharding.table.reference
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/sharding/databases/{database}/table-reference-rules
- shardingsphere://features/sharding/databases/{database}/table-reference-rules/{rule}
@@ -900,8 +925,13 @@ tools:
additionalProperties: false
outputSchema: *workflowPlanOutputSchema
annotations: *planningAnnotations
+ runtime: *planningRuntime
meta:
org.apache.shardingsphere/workflow-kind: sharding.default.strategy
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/sharding/algorithm-plugins
- shardingsphere://features/sharding/databases/{database}/default-strategy
@@ -929,8 +959,13 @@ tools:
additionalProperties: false
outputSchema: *workflowPlanOutputSchema
annotations: *planningAnnotations
+ runtime: *planningRuntime
meta:
org.apache.shardingsphere/workflow-kind: sharding.key.generator
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/sharding/key-generate-algorithm-plugins
- shardingsphere://features/sharding/databases/{database}/key-generators
@@ -962,8 +997,13 @@ tools:
additionalProperties: false
outputSchema: *workflowPlanOutputSchema
annotations: *planningAnnotations
+ runtime: *planningRuntime
meta:
org.apache.shardingsphere/workflow-kind: sharding.key.generate.strategy
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/sharding/key-generate-algorithm-plugins
- shardingsphere://features/sharding/databases/{database}/key-generators
@@ -991,8 +1031,13 @@ tools:
additionalProperties: false
outputSchema: *workflowPlanOutputSchema
annotations: *planningAnnotations
+ runtime: *planningRuntime
meta:
org.apache.shardingsphere/workflow-kind: sharding.component.cleanup
+ org.apache.shardingsphere/artifact-categories:
+ - rule_distsql
+ org.apache.shardingsphere/side-effect-scope:
+ - rule-metadata
org.apache.shardingsphere/related-resource-uris:
- shardingsphere://features/sharding/databases/{database}/unused-algorithms
- shardingsphere://features/sharding/databases/{database}/unused-key-generators
diff --git a/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-rule-component-cleanup.md b/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-rule-component-cleanup.md
index 7b4290acfad..b1847e0d4bd 100644
--- a/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-rule-component-cleanup.md
+++ b/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-rule-component-cleanup.md
@@ -5,4 +5,13 @@ Inputs:
- operation_type: {{operation_type}}
- plan_id: {{plan_id}}
-Plan cleanup only with `DROP SHARDING ALGORITHM`, `DROP SHARDING KEY GENERATOR`, or `DROP SHARDING AUDITOR`. First read unused and used-by resources; do not plan cleanup when the component is still referenced.
+Plan cleanup only with `DROP SHARDING ALGORITHM`, `DROP SHARDING KEY GENERATOR`, or `DROP SHARDING AUDITOR`.
+
+Before planning:
+- Read the unused component resource that matches the requested component type.
+- Read the matching used-by resource before dropping a named component.
+- Do not plan cleanup when the component is still referenced by any table rule, strategy, or auditor binding.
+
+Ask before planning when database, component_type, or component_name is unclear.
+
+Stop after returning a plan_id with reviewable cleanup DistSQL, or after explaining why cleanup is unsafe.
diff --git a/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-table-rule.md b/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-table-rule.md
index e3db67b9a02..407e877b89c 100644
--- a/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-table-rule.md
+++ b/mcp/features/sharding/src/main/resources/META-INF/shardingsphere-mcp/prompts/plan-sharding-table-rule.md
@@ -6,4 +6,17 @@ Inputs:
- algorithm_type: {{algorithm_type}}
- plan_id: {{plan_id}}
-Plan only ShardingSphere sharding table rule DistSQL. Do not create physical databases, physical tables, indexes, storage units, migrations, backfills, or data probes. If data nodes, table, standard sharding column, complex sharding columns, strategy type, or algorithm details are missing for the selected strategy, ask for them before planning.
+Plan only ShardingSphere sharding table rule DistSQL.
+
+Before planning:
+- Read existing table rules, algorithm plugins, and key-generate algorithm plugins for the logical database.
+- Preserve existing rule details that the user did not ask to change.
+- Do not create physical databases, physical tables, indexes, storage units, migrations, backfills, or data probes.
+
+Ask before planning when any required rule input is unclear:
+- logical table and actual data nodes
+- strategy type and required sharding column or columns
+- sharding algorithm type and required properties
+- key generator, auditor, or generated key column when the requested rule needs them
+
+Stop after returning a plan_id with reviewable DistSQL artifacts, or after listing the missing inputs.
diff --git a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidatorTest.java b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidatorTest.java
index 9d234ca8f47..8493b947386 100644
--- a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidatorTest.java
+++ b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/descriptor/ShardingToolDescriptorValidatorTest.java
@@ -58,15 +58,19 @@ class ShardingToolDescriptorValidatorTest {
@Test
void assertExposeCompletionTargets() {
MCPCompletionTargetDescriptor algorithmCompletionTarget = findCompletionTarget("prompt", ShardingFeatureDefinition.PLAN_TABLE_RULE_PROMPT_NAME);
- assertThat(algorithmCompletionTarget.getArguments(), is(List.of("algorithm_type")));
+ assertThat(algorithmCompletionTarget.getArguments(), is(List.of("database", "algorithm_type")));
assertThat(algorithmCompletionTarget.getMaxValues(), is(50));
+ MCPCompletionTargetDescriptor tableReferenceCompletionTarget = findCompletionTarget("prompt", ShardingFeatureDefinition.PLAN_TABLE_REFERENCE_PROMPT_NAME);
+ assertThat(tableReferenceCompletionTarget.getArguments(), is(List.of("database")));
MCPCompletionTargetDescriptor defaultStrategyCompletionTarget = findCompletionTarget("prompt", ShardingFeatureDefinition.PLAN_DEFAULT_STRATEGY_PROMPT_NAME);
- assertThat(defaultStrategyCompletionTarget.getArguments(), is(List.of("algorithm_type")));
+ assertThat(defaultStrategyCompletionTarget.getArguments(), is(List.of("database", "algorithm_type")));
MCPCompletionTargetDescriptor keyGeneratorCompletionTarget = findCompletionTarget("prompt", ShardingFeatureDefinition.PLAN_KEY_GENERATOR_PROMPT_NAME);
- assertThat(keyGeneratorCompletionTarget.getArguments(), is(List.of("key_generator_type")));
+ assertThat(keyGeneratorCompletionTarget.getArguments(), is(List.of("database", "key_generator_type")));
assertThat(keyGeneratorCompletionTarget.getMaxValues(), is(50));
MCPCompletionTargetDescriptor keyGenerateStrategyCompletionTarget = findCompletionTarget("prompt", ShardingFeatureDefinition.PLAN_KEY_GENERATE_STRATEGY_PROMPT_NAME);
- assertThat(keyGenerateStrategyCompletionTarget.getArguments(), is(List.of("key_generator_type")));
+ assertThat(keyGenerateStrategyCompletionTarget.getArguments(), is(List.of("database", "key_generator_type")));
+ MCPCompletionTargetDescriptor cleanupCompletionTarget = findCompletionTarget("prompt", ShardingFeatureDefinition.PLAN_COMPONENT_CLEANUP_PROMPT_NAME);
+ assertThat(cleanupCompletionTarget.getArguments(), is(List.of("database")));
assertFalse(hasCompletionTarget("resource", ShardingFeatureDefinition.ALGORITHM_PLUGINS_RESOURCE_URI));
assertFalse(hasCompletionTarget("resource", ShardingFeatureDefinition.KEY_GENERATE_ALGORITHM_PLUGINS_RESOURCE_URI));
}
@@ -147,6 +151,7 @@ class ShardingToolDescriptorValidatorTest {
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/workflow-kind"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/related-resource-uris"));
assertTrue(descriptor.getMeta().containsKey("org.apache.shardingsphere/follow-up-tools"));
+ assertTrue(MCPDescriptorCatalogIndex.findToolRuntimeDescriptor(each).filter(optional -> "plan".equals(optional.getWorkflowRole())).isPresent());
}
}
@@ -209,7 +214,8 @@ class ShardingToolDescriptorValidatorTest {
}
private static Stream<String> requiredMetadataFields() {
- return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
+ return Stream.of("org.apache.shardingsphere/workflow-kind", "org.apache.shardingsphere/artifact-categories", "org.apache.shardingsphere/side-effect-scope",
+ "org.apache.shardingsphere/related-resource-uris", "org.apache.shardingsphere/follow-up-tools");
}
private String readResource(final String resourceName) throws IOException {
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilder.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilder.java
index 29f8bf66272..243c696748a 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilder.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilder.java
@@ -76,7 +76,7 @@ final class MCPModelFirstContractPayloadBuilder {
result.put("workflow_session_rule", "Reuse the current-session plan_id returned by a planning tool; re-plan when the plan is unavailable.");
result.put("side_effect_rule", "Preview before side effects and continue only when the requested side effect is still intended.");
result.put("next_action_rule", "Use canonical next_actions fields: type, tool_name, resource_uri, and arguments.");
- result.put("detail_resource_rule", "Read each resource payload_contract before assuming detail fields.");
+ result.put("detail_resource_rule", "Use resource descriptors, outputSchema, and returned payload keys before assuming detail fields.");
result.put("recovery_rule", "When a call fails with recovery.next_actions, follow those structured actions before inventing a new call.");
return result;
}
diff --git a/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-support.yaml b/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-support.yaml
index c7c21d3fdcd..95d41e60621 100644
--- a/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-support.yaml
+++ b/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-support.yaml
@@ -114,11 +114,23 @@ prompts:
- database_gateway_validate_workflow
- database_gateway_plan_encrypt_rule
- database_gateway_plan_mask_rule
+ - database_gateway_plan_broadcast_rule
+ - database_gateway_plan_readwrite_splitting_rule
+ - database_gateway_plan_readwrite_splitting_status
+ - database_gateway_plan_shadow_rule
+ - database_gateway_plan_default_shadow_algorithm
+ - database_gateway_plan_shadow_algorithm_cleanup
+ - database_gateway_plan_sharding_table_rule
+ - database_gateway_plan_sharding_table_reference_rule
+ - database_gateway_plan_sharding_default_strategy
+ - database_gateway_plan_sharding_key_generator
+ - database_gateway_plan_sharding_key_generate_strategy
+ - database_gateway_plan_sharding_rule_component_cleanup
org.apache.shardingsphere/stop-conditions:
- "Stop after database_gateway_validate_workflow confirms the current plan or after a replacement plan is created."
- "Stop when the plan_id is unavailable and the matching planning tool needs fresh user inputs."
org.apache.shardingsphere/ask-user-conditions:
- - "Ask which workflow kind to re-plan when the failure summary does not identify encrypt or mask."
+ - "Ask which workflow kind to re-plan when the failure summary or recovery payload does not identify the matching planning tool."
- "Ask before applying recovered artifacts that would change runtime state."
completionTargets:
@@ -347,6 +359,9 @@ tools:
reason:
type: string
description: "Why the model should take the action."
+ question:
+ type: string
+ description: "Question to ask the user when type is ask_user."
required_inputs:
type: array
description: "User inputs required when type is ask_user."
diff --git a/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/prompts/recover-workflow.md b/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/prompts/recover-workflow.md
index 86cec81a7f9..db8fc43777c 100644
--- a/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/prompts/recover-workflow.md
+++ b/mcp/support/src/main/resources/META-INF/shardingsphere-mcp/prompts/recover-workflow.md
@@ -26,11 +26,11 @@ Model path:
2. If plan_id is missing or an MCP response says it is unknown or unavailable, call the matching planning tool again.
3. Use database_gateway_validate_workflow when the plan has been applied and the user asks whether runtime state matches the plan.
4. Use database_gateway_apply_workflow only after reviewing plan artifacts or an execution_mode=preview response with the user.
-5. Preserve user-provided corrections when re-planning with database_gateway_plan_encrypt_rule or database_gateway_plan_mask_rule.
+5. Preserve user-provided corrections when re-planning with the matching database_gateway_plan_* tool.
6. Before choosing uncertain plan_id or workflow handles, use completion/complete or read the nearest workflow resource; do not guess current-session identifiers.
Ask-user conditions:
-- Ask which workflow kind to re-plan when the failure summary does not identify encrypt or mask.
+- Ask which workflow kind to re-plan when the failure summary or recovery payload does not identify the matching planning tool.
- Ask before applying recovered artifacts that would change runtime state.
Stop conditions:
diff --git a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilderTest.java b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilderTest.java
index d52edf45b17..8f256ad7986 100644
--- a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilderTest.java
+++ b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPModelFirstContractPayloadBuilderTest.java
@@ -61,6 +61,7 @@ class MCPModelFirstContractPayloadBuilderTest {
assertThat(actual.get("metadata_first_resource"), is("shardingsphere://databases"));
assertTrue(String.valueOf(actual.get("preflight_rule")).contains("database_gateway_validate_runtime_database"));
assertThat(actual.get("side_effect_rule"), is("Preview before side effects and continue only when the requested side effect is still intended."));
+ assertThat(actual.get("detail_resource_rule"), is("Use resource descriptors, outputSchema, and returned payload keys before assuming detail fields."));
}
@Test
diff --git a/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/container/adapter/impl/ShardingSphereProxyEmbeddedContainer.java b/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/container/adapter/impl/ShardingSphereProxyEmbeddedContainer.java
index 8cf6282aeef..a9c9bc6ed31 100644
--- a/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/container/adapter/impl/ShardingSphereProxyEmbeddedContainer.java
+++ b/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/container/adapter/impl/ShardingSphereProxyEmbeddedContainer.java
@@ -17,6 +17,7 @@
package org.apache.shardingsphere.test.e2e.env.container.adapter.impl;
+import io.netty.channel.ChannelFuture;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@@ -51,6 +52,7 @@ import javax.sql.DataSource;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -59,6 +61,7 @@ import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
@@ -89,6 +92,8 @@ public final class ShardingSphereProxyEmbeddedContainer implements EmbeddedE2ECo
@Getter
private final Set<Startable> dependencies = new HashSet<>();
+ private int actualProxyPort;
+
private ShardingSphereProxy proxy;
public ShardingSphereProxyEmbeddedContainer(final DatabaseType databaseType, final AdaptorContainerConfiguration config) {
@@ -104,6 +109,15 @@ public final class ShardingSphereProxyEmbeddedContainer implements EmbeddedE2ECo
Collections.addAll(this.dependencies, dependencies);
}
+ /**
+ * Get proxy port.
+ *
+ * @return proxy port
+ */
+ public int getProxyPort() {
+ return 0 == actualProxyPort ? proxyPort : actualProxyPort;
+ }
+
@Override
public void start() {
dependencies.forEach(Startable::start);
@@ -117,10 +131,15 @@ public final class ShardingSphereProxyEmbeddedContainer implements EmbeddedE2ECo
new BootstrapInitializer().init(yamlConfig, proxyPort);
ProxySSLContext.init();
proxy = new ShardingSphereProxy();
- proxy.startInternal(proxyPort, Collections.singletonList("0.0.0.0"));
+ List<ChannelFuture> channelFutures = proxy.startInternal(proxyPort, Collections.singletonList("0.0.0.0"));
+ actualProxyPort = getBoundPort(channelFutures);
log.info("ShardingSphere-Proxy {} mode started successfully", ProxyContext.getInstance().getContextManager().getComputeNodeInstanceContext().getModeConfiguration().getType());
}
+ private int getBoundPort(final List<ChannelFuture> channelFutures) {
+ return ((InetSocketAddress) channelFutures.iterator().next().channel().localAddress()).getPort();
+ }
+
private Path getTempConfigurationDirectory() throws IOException {
Map<String, String> networkAliasAndHostLinkMap = getNetworkAliasAndHostLinkMap();
Map<String, String> storageConnectionInfoMap = getStorageConnectionInfoMap();
@@ -218,7 +237,7 @@ public final class ShardingSphereProxyEmbeddedContainer implements EmbeddedE2ECo
if (null == dataSource) {
StorageContainerConnectOption storageContainerConnectOption = DatabaseTypedSPILoader.getService(StorageContainerOption.class, databaseType).getConnectOption();
targetDataSourceProvider.set(StorageContainerUtils.generateDataSource(storageContainerConnectOption.getURL(
- "127.0.0.1", proxyPort, config.getProxyDataSourceName()), ProxyContainerConstants.USER, ProxyContainerConstants.PASSWORD, 2));
+ "127.0.0.1", getProxyPort(), config.getProxyDataSourceName()), ProxyContainerConstants.USER, ProxyContainerConstants.PASSWORD, 2));
}
return targetDataSourceProvider.get();
}
@@ -230,6 +249,8 @@ public final class ShardingSphereProxyEmbeddedContainer implements EmbeddedE2ECo
@Override
public void stop() {
- proxy.close();
+ if (null != proxy) {
+ proxy.close();
+ }
}
}
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 3fd99bb4310..ca3a60d6184 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
@@ -55,6 +55,9 @@ final class LLMMCPModelFacingToolResponseFormatter {
copyIfPresent(response, result, "count");
copyIfPresent(response, result, "has_more");
copyIfPresent(response, result, "total_match_count");
+ copyIfPresent(response, result, "returned_count");
+ copyIfPresent(response, result, "truncated");
+ copyIfPresent(response, result, "large_result_guidance");
copyIfPresent(response, result, "search_context");
copyIfPresent(response, result, "ambiguity_state");
List<Map<String, Object>> resources = LLMMCPJsonValues.castToList(response.get("resources"));
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java
index 7a74ef9395b..ace56833999 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/production/AbstractProductionMySQLRuntimeE2ETest.java
@@ -316,7 +316,15 @@ abstract class AbstractProductionMySQLRuntimeE2ETest extends AbstractTransportPa
assertThat(String.valueOf(actual.get("preview_semantics")), is("classification_only"));
assertFalse((Boolean) actual.get("would_execute"));
List<Map<String, Object>> nextActions = getMapList(actual.get("next_actions"));
- assertThat(nextActions.stream().map(each -> String.valueOf(each.get("type"))).toList(), is(List.of("tool_call")));
+ assertThat(nextActions.stream().map(each -> String.valueOf(each.get("type"))).toList(), is(List.of("ask_user", "tool_call")));
+ Map<String, Object> askUserAction = nextActions.getFirst();
+ assertThat(askUserAction.get("order"), is(1));
+ assertThat(askUserAction.get("required_inputs"), is(List.of("execution_approved")));
+ Map<String, Object> toolCallAction = nextActions.get(1);
+ assertThat(toolCallAction.get("order"), is(2));
+ assertThat(toolCallAction.get("tool_name"), is("database_gateway_execute_update"));
+ assertThat(toolCallAction.get("depends_on"), is(List.of(1)));
+ assertThat(getMap(toolCallAction.get("arguments")).get("execution_mode"), is("execute"));
}
protected void assertAiNativeSqlResult(final MCPInteractionClient interactionClient) throws IOException, InterruptedException {
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java
index cd6cfaddab3..2d87cfa6628 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/runtime/programmatic/HttpTransportBaselineContractE2ETest.java
@@ -18,6 +18,9 @@
package org.apache.shardingsphere.test.e2e.mcp.runtime.programmatic;
import org.apache.shardingsphere.mcp.support.descriptor.MCPShardingSphereMetadataKeys;
+import org.apache.shardingsphere.mcp.api.resource.MCPUriVariables;
+import org.apache.shardingsphere.mcp.core.context.MCPServiceHandlerContext;
+import org.apache.shardingsphere.mcp.core.resource.handler.capability.ServerCapabilitiesHandler;
import org.apache.shardingsphere.test.e2e.mcp.env.MCPE2ECondition;
import org.apache.shardingsphere.test.e2e.mcp.support.assertion.MCPBaselineContractAssertions;
import org.junit.jupiter.api.Test;
@@ -33,8 +36,8 @@ import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
-@EnabledIf("isEnabled")
class HttpTransportBaselineContractE2ETest extends AbstractSharedHttpProgrammaticRuntimeE2ETest {
private static final String BASELINE_RESOURCE_PATH = "baseline-contract/model-contract/";
@@ -44,6 +47,7 @@ class HttpTransportBaselineContractE2ETest extends AbstractSharedHttpProgrammati
}
@Test
+ @EnabledIf("isEnabled")
void assertCapabilitiesBaselineContract() throws IOException, InterruptedException {
launchHttpTransport();
HttpClient httpClient = HttpClient.newHttpClient();
@@ -53,6 +57,12 @@ class HttpTransportBaselineContractE2ETest extends AbstractSharedHttpProgrammati
MCPBaselineContractAssertions.assertMatchesNormalizedBaselineContract(BASELINE_RESOURCE_PATH + "capabilities.yaml", createCapabilitiesContract(getFirstResourcePayload(actual.body())));
}
+ @Test
+ void assertCapabilitiesBaselineContractProjection() {
+ Map<String, Object> actual = new ServerCapabilitiesHandler().handle(mock(MCPServiceHandlerContext.class), new MCPUriVariables(Map.of())).toPayload();
+ MCPBaselineContractAssertions.assertMatchesNormalizedBaselineContract(BASELINE_RESOURCE_PATH + "capabilities.yaml", createCapabilitiesContract(actual));
+ }
+
private Map<String, Object> createCapabilitiesContract(final Map<String, Object> payload) {
Map<String, Object> result = new LinkedHashMap<>(12, 1F);
result.put("response_mode", payload.get("response_mode"));
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/ProxyEncryptWorkflowRuntimeTestSupport.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/ProxyEncryptWorkflowRuntimeTestSupport.java
index 63f65878f15..22ae3b879b7 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/ProxyEncryptWorkflowRuntimeTestSupport.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/ProxyEncryptWorkflowRuntimeTestSupport.java
@@ -27,8 +27,6 @@ import org.apache.shardingsphere.test.e2e.env.container.adapter.config.AdaptorCo
import org.apache.shardingsphere.test.e2e.env.container.adapter.impl.ShardingSphereProxyEmbeddedContainer;
import org.testcontainers.containers.GenericContainer;
-import java.io.IOException;
-import java.net.ServerSocket;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
@@ -59,43 +57,30 @@ public final class ProxyEncryptWorkflowRuntimeTestSupport {
* @throws SQLException SQL exception
*/
public static ProxyEncryptWorkflowRuntimeFixture createFixture() throws SQLException {
- int proxyPort = allocateProxyPort();
GenericContainer<?> storageContainer = MySQLRuntimeTestSupport.createContainer().withNetworkAliases(STORAGE_NETWORK_ALIAS);
- ShardingSphereProxyEmbeddedContainer proxyContainer = createProxyContainer(proxyPort);
+ ShardingSphereProxyEmbeddedContainer proxyContainer = createProxyContainer();
boolean success = false;
- boolean proxyContainerStarted = false;
storageContainer.start();
try {
MySQLRuntimeTestSupport.initializeDatabase(storageContainer);
proxyContainer.dependsOn(storageContainer);
proxyContainer.start();
- proxyContainerStarted = true;
success = true;
- return new ProxyEncryptWorkflowRuntimeFixture(storageContainer, proxyContainer, createRuntimeDatabases(proxyPort));
+ return new ProxyEncryptWorkflowRuntimeFixture(storageContainer, proxyContainer, createRuntimeDatabases(proxyContainer.getProxyPort()));
} finally {
if (!success) {
- if (proxyContainerStarted) {
- proxyContainer.stop();
- }
+ proxyContainer.stop();
storageContainer.stop();
}
}
}
- private static int allocateProxyPort() {
- try (ServerSocket serverSocket = new ServerSocket(0)) {
- return serverSocket.getLocalPort();
- } catch (final IOException ex) {
- throw new IllegalStateException("Failed to allocate Proxy port.", ex);
- }
- }
-
- private static ShardingSphereProxyEmbeddedContainer createProxyContainer(final int proxyPort) {
+ private static ShardingSphereProxyEmbeddedContainer createProxyContainer() {
DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "MySQL");
Map<String, String> mountedResources = new LinkedHashMap<>(2, 1F);
mountedResources.put("/proxy/workflow/global.yaml", "/opt/shardingsphere-proxy/conf/global.yaml");
mountedResources.put("/proxy/workflow/database-logic-db.yaml", "/opt/shardingsphere-proxy/conf/database-logic-db.yaml");
- return new ShardingSphereProxyEmbeddedContainer(databaseType, new AdaptorContainerConfiguration(LOGICAL_DATABASE_NAME, List.of(), mountedResources, "", ""), proxyPort);
+ return new ShardingSphereProxyEmbeddedContainer(databaseType, new AdaptorContainerConfiguration(LOGICAL_DATABASE_NAME, List.of(), mountedResources, "", ""), 0);
}
private static Map<String, RuntimeDatabaseConfiguration> createRuntimeDatabases(final int proxyPort) {
diff --git a/test/e2e/mcp/src/test/resources/baseline-contract/model-contract/capabilities.yaml b/test/e2e/mcp/src/test/resources/baseline-contract/model-contract/capabilities.yaml
index e87effa3806..f6e77c51364 100644
--- a/test/e2e/mcp/src/test/resources/baseline-contract/model-contract/capabilities.yaml
+++ b/test/e2e/mcp/src/test/resources/baseline-contract/model-contract/capabilities.yaml
@@ -72,8 +72,8 @@ model_contract:
side effect is still intended.
next_action_rule: 'Use canonical next_actions fields: type, tool_name, resource_uri,
and arguments.'
- detail_resource_rule: Read each resource payload_contract before assuming detail
- fields.
+ detail_resource_rule: Use resource descriptors, outputSchema, and returned payload
+ keys before assuming detail fields.
recovery_rule: When a call fails with recovery.next_actions, follow those structured
actions before inventing a new call.
surface_summary:
@@ -896,6 +896,10 @@ prompts:
- {name: schema, required: false}
- {name: sql_intent, required: true}
completionTargets:
+- referenceType: prompt
+ reference: plan_broadcast_rule
+ arguments: [database]
+ maxValues: 50
- referenceType: resource
reference: shardingsphere://databases/{database}
arguments: [database]
@@ -974,31 +978,47 @@ completionTargets:
maxValues: 50
- referenceType: prompt
reference: plan_readwrite_splitting_rule
- arguments: [load_balancer_type]
+ arguments: [database, load_balancer_type]
+ maxValues: 50
+- referenceType: prompt
+ reference: plan_readwrite_splitting_status
+ arguments: [database]
maxValues: 50
- referenceType: prompt
reference: plan_shadow_rule
- arguments: [algorithm_type]
+ arguments: [database, algorithm_type]
maxValues: 50
- referenceType: prompt
reference: plan_default_shadow_algorithm
- arguments: [algorithm_type]
+ arguments: [database, algorithm_type]
+ maxValues: 50
+- referenceType: prompt
+ reference: plan_shadow_algorithm_cleanup
+ arguments: [database]
maxValues: 50
- referenceType: prompt
reference: plan_sharding_table_rule
- arguments: [algorithm_type]
+ arguments: [database, algorithm_type]
+ maxValues: 50
+- referenceType: prompt
+ reference: plan_sharding_table_reference_rule
+ arguments: [database]
maxValues: 50
- referenceType: prompt
reference: plan_sharding_default_strategy
- arguments: [algorithm_type]
+ arguments: [database, algorithm_type]
maxValues: 50
- referenceType: prompt
reference: plan_sharding_key_generator
- arguments: [key_generator_type]
+ arguments: [database, key_generator_type]
maxValues: 50
- referenceType: prompt
reference: plan_sharding_key_generate_strategy
- arguments: [key_generator_type]
+ arguments: [database, key_generator_type]
+ maxValues: 50
+- referenceType: prompt
+ reference: plan_sharding_rule_component_cleanup
+ arguments: [database]
maxValues: 50
- referenceType: prompt
reference: inspect_metadata