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 d4d615e3de4 Refine MCP workflow plan completion (#39021)
d4d615e3de4 is described below
commit d4d615e3de4702ff04be250eb5b6590b10793a0a
Author: Liang Zhang <[email protected]>
AuthorDate: Mon Jul 6 18:50:00 2026 +0800
Refine MCP workflow plan completion (#39021)
- scope plan_id completion by prompt workflow kind
- align planning descriptor next_actions with apply workflow preview
- tighten feature completion argument contract tests
---
.../MCPCompletionSpecificationFactoryTest.java | 22 ++++++++++-
.../provider/WorkflowPlanIdCompletionProvider.java | 15 +++++--
.../broadcast/BroadcastFeatureDefinitionTest.java | 3 +-
.../mcp-descriptors/mcp-descriptor-encrypt.yaml | 4 +-
.../encrypt/EncryptDescriptorContractTest.java | 7 +++-
.../mcp-descriptors/mcp-descriptor-mask.yaml | 4 +-
.../feature/mask/MaskFeatureDefinitionTest.java | 3 +-
.../ReadwriteSplittingFeatureDefinitionTest.java | 5 +--
.../mcp-descriptors/mcp-descriptor-shadow.yaml | 30 ++++++++++++--
.../shadow/ShadowDescriptorContractTest.java | 5 +--
.../mcp-descriptors/mcp-descriptor-sharding.yaml | 10 ++++-
.../sharding/ShardingDescriptorContractTest.java | 3 +-
.../descriptor/MCPDescriptorCatalogIndex.java | 46 ++++++++++++++++++++++
.../descriptor/MCPDescriptorCatalogIndexTest.java | 12 ++++++
.../mcp-descriptor-test-planning.yaml | 4 +-
15 files changed, 148 insertions(+), 25 deletions(-)
diff --git
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/completion/MCPCompletionSpecificationFactoryTest.java
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/completion/MCPCompletionSpecificationFactoryTest.java
index 5434876f066..636a3b9f6f7 100644
---
a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/completion/MCPCompletionSpecificationFactoryTest.java
+++
b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/completion/MCPCompletionSpecificationFactoryTest.java
@@ -28,6 +28,7 @@ import
org.apache.shardingsphere.mcp.support.database.metadata.jdbc.RuntimeDatab
import
org.apache.shardingsphere.mcp.support.descriptor.MCPShardingSphereMetadataKeys;
import org.apache.shardingsphere.mcp.support.workflow.WorkflowSessionContext;
import
org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnapshot;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowKind;
import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowLifecycle;
import org.junit.jupiter.api.Test;
@@ -151,6 +152,19 @@ class MCPCompletionSpecificationFactoryTest {
assertThat(((Map<?, ?>) ((List<?>)
actual.meta().get(MCPShardingSphereMetadataKeys.VALUE_DETAILS)).getFirst()).get("rankingReason"),
is("recent-plan-first-for-plan_id"));
}
+ @Test
+ void assertCompletePlanIdsByPromptWorkflowKind() {
+ WorkflowSessionContext workflowSessionContext = new
InMemoryWorkflowSessionContext();
+ workflowSessionContext.save(createSnapshot("encrypt-plan",
"session-1", "encrypt.rule", WorkflowLifecycle.STATUS_PLANNED));
+ workflowSessionContext.save(createSnapshot("mask-plan", "session-1",
"mask.rule", WorkflowLifecycle.STATUS_PLANNED));
+ SyncCompletionSpecification completionSpecification =
findCompletion(createFactory(createRuntimeContext(workflowSessionContext)).createCompletionSpecifications(),
+ new McpSchema.PromptReference("plan_encrypt_rule"));
+ McpSchema.CompleteResult actual =
completionSpecification.completionHandler().apply(createExchange("session-1"),
+ new McpSchema.CompleteRequest(new
McpSchema.PromptReference("plan_encrypt_rule"), new
McpSchema.CompleteRequest.CompleteArgument("plan_id", "")));
+ assertThat(actual.completion().values(), is(List.of("encrypt-plan")));
+ assertThat(actual.completion().total(), is(1));
+ }
+
@Test
void assertCompletePlanIdsWithExactMatchFirst() {
WorkflowSessionContext workflowSessionContext =
mock(WorkflowSessionContext.class);
@@ -200,7 +214,13 @@ class MCPCompletionSpecificationFactoryTest {
}
private WorkflowContextSnapshot createSnapshot(final String planId, final
String sessionId, final String status) {
- return createSnapshot(planId, sessionId, status, null);
+ return createSnapshot(planId, sessionId, status, (Instant) null);
+ }
+
+ private WorkflowContextSnapshot createSnapshot(final String planId, final
String sessionId, final String workflowKind, final String status) {
+ WorkflowContextSnapshot result = createSnapshot(planId, sessionId,
status);
+ result.setWorkflowKind(WorkflowKind.valueOf(workflowKind));
+ return result;
}
private WorkflowContextSnapshot createSnapshot(final String planId, final
String sessionId, final String status, final Instant updateTime) {
diff --git
a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/completion/provider/WorkflowPlanIdCompletionProvider.java
b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/completion/provider/WorkflowPlanIdCompletionProvider.java
index 3eb624f73ba..7c3aec667cc 100644
---
a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/completion/provider/WorkflowPlanIdCompletionProvider.java
+++
b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/completion/provider/WorkflowPlanIdCompletionProvider.java
@@ -21,11 +21,13 @@ import
org.apache.shardingsphere.mcp.support.completion.MCPCompletionCandidate;
import org.apache.shardingsphere.mcp.support.completion.MCPCompletionProvider;
import
org.apache.shardingsphere.mcp.support.completion.MCPCompletionProviderResult;
import
org.apache.shardingsphere.mcp.support.completion.MCPCompletionRequestContext;
+import
org.apache.shardingsphere.mcp.support.descriptor.MCPDescriptorCatalogIndex;
import
org.apache.shardingsphere.mcp.support.workflow.MCPWorkflowHandlerContext;
import
org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnapshot;
import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowFieldNames;
import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowLifecycle;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -50,11 +52,14 @@ public final class WorkflowPlanIdCompletionProvider
implements MCPCompletionProv
@Override
public MCPCompletionProviderResult complete(final
MCPWorkflowHandlerContext handlerContext, final MCPCompletionRequestContext
requestContext) {
- return new MCPCompletionProviderResult(completePlanIds(handlerContext,
requestContext.getSessionId()));
+ return new MCPCompletionProviderResult(completePlanIds(handlerContext,
requestContext));
}
- private List<MCPCompletionCandidate> completePlanIds(final
MCPWorkflowHandlerContext handlerContext, final String sessionId) {
- return
handlerContext.getWorkflowSessionContext().list(sessionId).stream().filter(this::isCompletionEligiblePlan)
+ private List<MCPCompletionCandidate> completePlanIds(final
MCPWorkflowHandlerContext handlerContext, final MCPCompletionRequestContext
requestContext) {
+ Collection<String> workflowKinds =
MCPDescriptorCatalogIndex.findWorkflowKindsByCompletionTarget(requestContext.getDescriptor());
+ return
handlerContext.getWorkflowSessionContext().list(requestContext.getSessionId()).stream()
+ .filter(this::isCompletionEligiblePlan)
+ .filter(each -> isAllowedWorkflowKind(each, workflowKinds))
.map(each -> new MCPCompletionCandidate(each.getPlanId(),
String.format("%s %s", each.getWorkflowKind(), each.getStatus()),
"workflow-session", each.getUpdateTime(),
"recent-plan-first-for-plan_id"))
.toList();
@@ -63,4 +68,8 @@ public final class WorkflowPlanIdCompletionProvider
implements MCPCompletionProv
private boolean isCompletionEligiblePlan(final WorkflowContextSnapshot
snapshot) {
return
COMPLETION_ELIGIBLE_WORKFLOW_STATUSES.contains(Objects.toString(snapshot.getStatus(),
""));
}
+
+ private boolean isAllowedWorkflowKind(final WorkflowContextSnapshot
snapshot, final Collection<String> workflowKinds) {
+ return workflowKinds.isEmpty() ||
workflowKinds.contains(Objects.toString(snapshot.getWorkflowKind(), ""));
+ }
}
diff --git
a/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/BroadcastFeatureDefinitionTest.java
b/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/BroadcastFeatureDefinitionTest.java
index a03133c4686..cc654c09cef 100644
---
a/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/BroadcastFeatureDefinitionTest.java
+++
b/mcp/features/broadcast/src/test/java/org/apache/shardingsphere/mcp/feature/broadcast/BroadcastFeatureDefinitionTest.java
@@ -25,7 +25,6 @@ import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertTrue;
class BroadcastFeatureDefinitionTest {
@@ -43,6 +42,6 @@ class BroadcastFeatureDefinitionTest {
void assertPromptCompletionArguments() {
MCPCompletionTargetDescriptor actual =
MCPDescriptorCatalogLoader.load().getShardingSphereDescriptors().getCompletionTargetDescriptors().stream()
.filter(each -> "prompt".equals(each.getReferenceType()) &&
BroadcastFeatureDefinition.PLAN_PROMPT_NAME.equals(each.getReference())).findFirst().orElseThrow();
- assertTrue(actual.getArguments().containsAll(List.of("database",
"table", "plan_id")));
+ assertThat(actual.getArguments(), is(List.of("database", "table",
"plan_id")));
}
}
diff --git
a/mcp/features/encrypt/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-encrypt.yaml
b/mcp/features/encrypt/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-encrypt.yaml
index 0f6b6da6543..76462bfd7f4 100644
---
a/mcp/features/encrypt/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-encrypt.yaml
+++
b/mcp/features/encrypt/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-encrypt.yaml
@@ -478,7 +478,9 @@ tools:
type: tool_call
title: Call database_gateway_apply_workflow
tool_name: database_gateway_apply_workflow
- arguments: {}
+ arguments:
+ plan_id: encrypt-rule-20260505-001
+ execution_mode: preview
reason: Preview generated encrypt rule DistSQL artifacts.
annotations:
title: Plan Encrypt Rule
diff --git
a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/EncryptDescriptorContractTest.java
b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/EncryptDescriptorContractTest.java
index c4884a680cd..f9c7c72fc3c 100644
---
a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/EncryptDescriptorContractTest.java
+++
b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/EncryptDescriptorContractTest.java
@@ -28,6 +28,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -47,7 +49,8 @@ class EncryptDescriptorContractTest {
@Test
void assertPromptCompletionArguments() {
-
assertCompletionTargetArguments(EncryptFeatureDefinition.PLAN_PROMPT_NAME,
"database", "schema", "table", "column", "plan_id");
+
assertCompletionTargetArguments(EncryptFeatureDefinition.PLAN_PROMPT_NAME,
"database", "schema", "table", "column", "algorithm_type",
"assisted_query_algorithm_type",
+ "like_query_algorithm_type", "plan_id");
}
private MCPToolDescriptor findToolDescriptor() {
@@ -59,7 +62,7 @@ class EncryptDescriptorContractTest {
private void assertCompletionTargetArguments(final String promptName,
final String... expectedArguments) {
MCPCompletionTargetDescriptor actual =
MCPDescriptorCatalogLoader.load().getShardingSphereDescriptors().getCompletionTargetDescriptors().stream()
.filter(each -> "prompt".equals(each.getReferenceType()) &&
promptName.equals(each.getReference())).findFirst().orElseThrow();
-
assertTrue(actual.getArguments().containsAll(List.of(expectedArguments)));
+ assertThat(actual.getArguments(), is(List.of(expectedArguments)));
}
private void assertEncryptDistSQLExampleValue(final Object value) {
diff --git
a/mcp/features/mask/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-mask.yaml
b/mcp/features/mask/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-mask.yaml
index 14572159980..dcf2ac10904 100644
---
a/mcp/features/mask/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-mask.yaml
+++
b/mcp/features/mask/src/main/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-mask.yaml
@@ -394,7 +394,9 @@ tools:
type: tool_call
title: Call database_gateway_apply_workflow
tool_name: database_gateway_apply_workflow
- arguments: {}
+ arguments:
+ plan_id: mask-rule-20260505-001
+ execution_mode: preview
reason: Preview generated mask rule DistSQL artifacts.
annotations:
title: Plan Mask Rule
diff --git
a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/MaskFeatureDefinitionTest.java
b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/MaskFeatureDefinitionTest.java
index bf5a1070fbf..1698de9b40e 100644
---
a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/MaskFeatureDefinitionTest.java
+++
b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/MaskFeatureDefinitionTest.java
@@ -25,7 +25,6 @@ import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertTrue;
class MaskFeatureDefinitionTest {
@@ -43,6 +42,6 @@ class MaskFeatureDefinitionTest {
void assertPromptCompletionArguments() {
MCPCompletionTargetDescriptor actual =
MCPDescriptorCatalogLoader.load().getShardingSphereDescriptors().getCompletionTargetDescriptors().stream()
.filter(each -> "prompt".equals(each.getReferenceType()) &&
MaskFeatureDefinition.PLAN_PROMPT_NAME.equals(each.getReference())).findFirst().orElseThrow();
- assertTrue(actual.getArguments().containsAll(List.of("database",
"schema", "table", "column", "plan_id")));
+ assertThat(actual.getArguments(), is(List.of("database", "schema",
"table", "column", "algorithm_type", "plan_id")));
}
}
diff --git
a/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/ReadwriteSplittingFeatureDefinitionTest.java
b/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/ReadwriteSplittingFeatureDefinitionTest.java
index af9af0f3883..29e8738ed1e 100644
---
a/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/ReadwriteSplittingFeatureDefinitionTest.java
+++
b/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/ReadwriteSplittingFeatureDefinitionTest.java
@@ -26,7 +26,6 @@ import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertTrue;
class ReadwriteSplittingFeatureDefinitionTest {
@@ -39,13 +38,13 @@ class ReadwriteSplittingFeatureDefinitionTest {
@Test
void assertPromptCompletionArguments() {
MCPDescriptorCatalog catalog = MCPDescriptorCatalogLoader.load();
- assertCompletionTargetArguments(catalog,
ReadwriteSplittingFeatureDefinition.PLAN_RULE_PROMPT_NAME, "database",
"write_storage_unit", "plan_id");
+ assertCompletionTargetArguments(catalog,
ReadwriteSplittingFeatureDefinition.PLAN_RULE_PROMPT_NAME, "database",
"write_storage_unit", "load_balancer_type", "plan_id");
assertCompletionTargetArguments(catalog,
ReadwriteSplittingFeatureDefinition.PLAN_STATUS_PROMPT_NAME, "database",
"storage_unit", "plan_id");
}
private void assertCompletionTargetArguments(final MCPDescriptorCatalog
catalog, final String promptName, final String... expectedArguments) {
MCPCompletionTargetDescriptor actual =
catalog.getShardingSphereDescriptors().getCompletionTargetDescriptors().stream()
.filter(each -> "prompt".equals(each.getReferenceType()) &&
promptName.equals(each.getReference())).findFirst().orElseThrow();
-
assertTrue(actual.getArguments().containsAll(List.of(expectedArguments)));
+ assertThat(actual.getArguments(), is(List.of(expectedArguments)));
}
}
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 ec673f023c0..5afbda9a43a 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
@@ -597,7 +597,15 @@ tools:
distsql_artifacts: []
resources_to_read: []
proxy_topology_hint: {}
- next_actions: []
+ next_actions:
+ - order: 1
+ type: tool_call
+ title: Call database_gateway_apply_workflow
+ tool_name: database_gateway_apply_workflow
+ arguments:
+ plan_id: shadow-rule-20260606-001
+ execution_mode: preview
+ reason: Preview generated shadow DistSQL artifacts.
annotations:
title: Plan Shadow Rule
destructiveHint: false
@@ -678,7 +686,15 @@ tools:
distsql_artifacts: []
resources_to_read: []
proxy_topology_hint: {}
- next_actions: []
+ next_actions:
+ - order: 1
+ type: tool_call
+ title: Call database_gateway_apply_workflow
+ tool_name: database_gateway_apply_workflow
+ arguments:
+ plan_id: default-shadow-algorithm-20260606-001
+ execution_mode: preview
+ reason: Preview generated default shadow algorithm DistSQL
artifacts.
annotations:
title: Plan Default Shadow Algorithm
destructiveHint: false
@@ -749,7 +765,15 @@ tools:
distsql_artifacts: []
resources_to_read: []
proxy_topology_hint: {}
- next_actions: []
+ next_actions:
+ - order: 1
+ type: tool_call
+ title: Call database_gateway_apply_workflow
+ tool_name: database_gateway_apply_workflow
+ arguments:
+ plan_id: shadow-algorithm-cleanup-20260606-001
+ execution_mode: preview
+ reason: Preview generated shadow algorithm cleanup DistSQL
artifacts.
annotations:
title: Plan Shadow Algorithm Cleanup
destructiveHint: false
diff --git
a/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/ShadowDescriptorContractTest.java
b/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/ShadowDescriptorContractTest.java
index 60aa42a5bd6..dab093c5e5d 100644
---
a/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/ShadowDescriptorContractTest.java
+++
b/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/ShadowDescriptorContractTest.java
@@ -29,7 +29,6 @@ import java.util.Map.Entry;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertTrue;
class ShadowDescriptorContractTest {
@@ -47,7 +46,7 @@ class ShadowDescriptorContractTest {
@Test
void assertPromptCompletionArguments() {
MCPDescriptorCatalog catalog = MCPDescriptorCatalogLoader.load();
- assertCompletionTargetArguments(catalog,
ShadowFeatureDefinition.PLAN_RULE_PROMPT_NAME, "database",
"source_storage_unit", "shadow_storage_unit", "plan_id");
+ assertCompletionTargetArguments(catalog,
ShadowFeatureDefinition.PLAN_RULE_PROMPT_NAME, "database",
"source_storage_unit", "shadow_storage_unit", "table", "algorithm_type",
"plan_id");
assertCompletionTargetArguments(catalog,
ShadowFeatureDefinition.PLAN_DEFAULT_ALGORITHM_PROMPT_NAME, "database",
"algorithm_type", "plan_id");
assertCompletionTargetArguments(catalog,
ShadowFeatureDefinition.PLAN_ALGORITHM_CLEANUP_PROMPT_NAME, "database",
"plan_id");
}
@@ -59,6 +58,6 @@ class ShadowDescriptorContractTest {
private void assertCompletionTargetArguments(final MCPDescriptorCatalog
catalog, final String promptName, final String... expectedArguments) {
MCPCompletionTargetDescriptor actual =
catalog.getShardingSphereDescriptors().getCompletionTargetDescriptors().stream()
.filter(each -> "prompt".equals(each.getReferenceType()) &&
promptName.equals(each.getReference())).findFirst().orElseThrow();
-
assertTrue(actual.getArguments().containsAll(List.of(expectedArguments)));
+ assertThat(actual.getArguments(), is(List.of(expectedArguments)));
}
}
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 c0cc64fb2d2..b6ba5ecd493 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
@@ -855,7 +855,15 @@ tools:
status: planned
missing_required_inputs: []
resources_to_read: []
- next_actions: []
+ next_actions:
+ - order: 1
+ type: tool_call
+ title: Call database_gateway_apply_workflow
+ tool_name: database_gateway_apply_workflow
+ arguments:
+ plan_id: sharding-table-rule-20260606-001
+ execution_mode: preview
+ reason: Preview generated sharding DistSQL artifacts.
annotations:
title: Plan Sharding Table Rule
destructiveHint: false
diff --git
a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/ShardingDescriptorContractTest.java
b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/ShardingDescriptorContractTest.java
index 82a11750c2c..ae882e5d3d2 100644
---
a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/ShardingDescriptorContractTest.java
+++
b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/ShardingDescriptorContractTest.java
@@ -29,7 +29,6 @@ import java.util.Map.Entry;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertTrue;
class ShardingDescriptorContractTest {
@@ -65,6 +64,6 @@ class ShardingDescriptorContractTest {
private void assertCompletionTargetArguments(final MCPDescriptorCatalog
catalog, final String promptName, final String... expectedArguments) {
MCPCompletionTargetDescriptor actual =
catalog.getShardingSphereDescriptors().getCompletionTargetDescriptors().stream()
.filter(each -> "prompt".equals(each.getReferenceType()) &&
promptName.equals(each.getReference())).findFirst().orElseThrow();
-
assertTrue(actual.getArguments().containsAll(List.of(expectedArguments)));
+ assertThat(actual.getArguments(), is(List.of(expectedArguments)));
}
}
diff --git
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndex.java
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndex.java
index 5778adf371a..e76e5793858 100644
---
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndex.java
+++
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndex.java
@@ -28,6 +28,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -57,6 +58,8 @@ public final class MCPDescriptorCatalogIndex {
private static final Map<String, String>
PLANNING_TOOL_NAMES_BY_WORKFLOW_KIND = createPlanningToolNamesByWorkflowKind();
+ private static final Map<String, Collection<String>>
WORKFLOW_KINDS_BY_PROMPT_NAME = createWorkflowKindsByPromptName();
+
private static Map<String, MCPResourceDescriptor>
createResourceDescriptors() {
int expectedSize =
CATALOG.getProtocolDescriptors().getResourceDescriptors().size() +
CATALOG.getProtocolDescriptors().getResourceTemplateDescriptors().size();
Map<String, MCPResourceDescriptor> result = new
LinkedHashMap<>(expectedSize, 1F);
@@ -109,6 +112,36 @@ public final class MCPDescriptorCatalogIndex {
return result;
}
+ private static Map<String, Collection<String>>
createWorkflowKindsByPromptName() {
+ Map<String, Collection<String>> result = new
LinkedHashMap<>(PROMPT_DESCRIPTORS.size(), 1F);
+ for (MCPPromptDescriptor each : PROMPT_DESCRIPTORS) {
+ Collection<String> workflowKinds =
findPromptPlanningWorkflowKind(each);
+ if (!workflowKinds.isEmpty()) {
+ result.put(each.getName(), workflowKinds);
+ }
+ }
+ return result;
+ }
+
+ private static Collection<String> findPromptPlanningWorkflowKind(final
MCPPromptDescriptor prompt) {
+ String planningToolName = "database_gateway_" + prompt.getName();
+ Object relatedTools =
prompt.getMeta().get(MCPShardingSphereMetadataKeys.RELATED_TOOLS);
+ MCPToolDescriptor toolDescriptor =
TOOL_DESCRIPTORS.get(planningToolName);
+ if (!(relatedTools instanceof Collection<?>)) {
+ return List.of();
+ }
+ if (!((Collection<?>) relatedTools).contains(planningToolName) || null
== toolDescriptor || !isPlanningTool(planningToolName)) {
+ return List.of();
+ }
+ String workflowKind =
Objects.toString(toolDescriptor.getMeta().get(MCPShardingSphereMetadataKeys.WORKFLOW_KIND),
"");
+ return workflowKind.isEmpty() ? List.of() : List.of(workflowKind);
+ }
+
+ private static boolean isPlanningTool(final String toolName) {
+ MCPToolRuntimeDescriptor runtimeDescriptor =
TOOL_RUNTIME_DESCRIPTORS.get(toolName);
+ return null != runtimeDescriptor &&
"plan".equals(runtimeDescriptor.getWorkflowRole());
+ }
+
/**
* Get resource descriptors.
*
@@ -198,6 +231,19 @@ public final class MCPDescriptorCatalogIndex {
return
Optional.ofNullable(PLANNING_TOOL_NAMES_BY_WORKFLOW_KIND.get(workflowKind));
}
+ /**
+ * Find workflow kinds related to a completion target.
+ *
+ * @param descriptor completion target descriptor
+ * @return related workflow kinds
+ */
+ public static Collection<String> findWorkflowKindsByCompletionTarget(final
MCPCompletionTargetDescriptor descriptor) {
+ if (!"prompt".equals(descriptor.getReferenceType())) {
+ return List.of();
+ }
+ return
WORKFLOW_KINDS_BY_PROMPT_NAME.getOrDefault(descriptor.getReference(),
List.of()).stream().toList();
+ }
+
/**
* Get completion target descriptors.
*
diff --git
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndexTest.java
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndexTest.java
index b45268d4eeb..c49cd26481a 100644
---
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndexTest.java
+++
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogIndexTest.java
@@ -107,6 +107,18 @@ class MCPDescriptorCatalogIndexTest {
assertFalse(MCPDescriptorCatalogIndex.findPlanningToolNameByWorkflowKind("unknown.rule").isPresent());
}
+ @Test
+ void assertFindWorkflowKindsByGenericPromptCompletionTarget() {
+ MCPCompletionTargetDescriptor descriptor = new
MCPCompletionTargetDescriptor("prompt", "recover_workflow", List.of("plan_id"),
50, Map.of());
+
assertTrue(MCPDescriptorCatalogIndex.findWorkflowKindsByCompletionTarget(descriptor).isEmpty());
+ }
+
+ @Test
+ void assertFindWorkflowKindsByResourceCompletionTarget() {
+ MCPCompletionTargetDescriptor descriptor = new
MCPCompletionTargetDescriptor("resource",
"shardingsphere://workflows/{plan_id}", List.of("plan_id"), 50, Map.of());
+
assertTrue(MCPDescriptorCatalogIndex.findWorkflowKindsByCompletionTarget(descriptor).isEmpty());
+ }
+
@Test
void assertGetCompletionTargetDescriptors() {
Collection<MCPCompletionTargetDescriptor> actualDescriptors =
MCPDescriptorCatalogIndex.getCompletionTargetDescriptors();
diff --git
a/mcp/support/src/test/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-test-planning.yaml
b/mcp/support/src/test/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-test-planning.yaml
index fb162f71163..f320c7dabb9 100644
---
a/mcp/support/src/test/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-test-planning.yaml
+++
b/mcp/support/src/test/resources/META-INF/shardingsphere-mcp/mcp-descriptors/mcp-descriptor-test-planning.yaml
@@ -200,7 +200,9 @@ tools:
type: tool_call
title: Call database_gateway_apply_workflow
tool_name: database_gateway_apply_workflow
- arguments: {}
+ arguments:
+ plan_id: encrypt-rule-20260505-001
+ execution_mode: preview
reason: Preview generated workflow artifacts.
annotations:
title: Plan Encrypt Rule