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 515df2adbf7 Improve MCP workflow continuation payloads (#39016)
515df2adbf7 is described below
commit 515df2adbf78bd72c6531617bb2bf153d68576b4
Author: Liang Zhang <[email protected]>
AuthorDate: Mon Jul 6 09:26:45 2026 +0800
Improve MCP workflow continuation payloads (#39016)
- Add model-facing summary fields to workflow planning, apply and
validation responses
- Return structured validation recovery next actions
- Align MCP guidance, descriptors, docs and descriptor validators with the
workflow contract
---
.../content/reference/mcp/protocol-surface.cn.md | 4 ++++
.../content/reference/mcp/protocol-surface.en.md | 4 ++++
.../shardingsphere-mcp/developer-appendix.cn.md | 5 +++++
.../shardingsphere-mcp/developer-appendix.en.md | 5 +++++
.../features/plugin-workflow.cn.md | 4 ++++
.../features/plugin-workflow.en.md | 4 ++++
.../workflow/WorkflowApplyResponseBuilder.java | 24 ++++++++++++++++++++--
.../workflow/WorkflowApplyResponseBuilderTest.java | 3 +++
.../mcp-descriptors/mcp-descriptor-broadcast.yaml | 4 ++++
.../mcp-descriptors/mcp-descriptor-encrypt.yaml | 4 ++++
.../encrypt/EncryptDescriptorContractTest.java | 8 ++++++++
.../mcp-descriptors/mcp-descriptor-mask.yaml | 4 ++++
.../mcp-descriptor-readwrite-splitting.yaml | 5 +++++
.../mcp-descriptors/mcp-descriptor-shadow.yaml | 6 ++++++
.../mcp-descriptors/mcp-descriptor-sharding.yaml | 2 ++
.../descriptor/MCPGuidancePayloadBuilder.java | 7 +++++++
.../MCPToolDescriptorCatalogValidator.java | 6 +++---
.../MCPToolDescriptorValidationUtils.java | 2 +-
.../service/WorkflowPlanPayloadBuilder.java | 18 +++++++++++++++-
.../service/WorkflowValidationSupport.java | 22 ++++++++++++++++++--
.../mcp-descriptors/mcp-descriptor-support.yaml | 8 ++++++++
.../descriptor/MCPDescriptorCatalogLoaderTest.java | 4 ++--
.../MCPDescriptorCatalogValidatorTest.java | 7 ++++---
.../descriptor/MCPGuidancePayloadBuilderTest.java | 10 ++++++++-
.../MCPToolDescriptorValidationUtilsTest.java | 2 +-
.../service/WorkflowPlanPayloadBuilderTest.java | 3 +++
.../service/WorkflowValidationSupportTest.java | 5 +++++
.../mcp-descriptor-test-planning.yaml | 4 ++++
28 files changed, 168 insertions(+), 16 deletions(-)
diff --git a/docs/document/content/reference/mcp/protocol-surface.cn.md
b/docs/document/content/reference/mcp/protocol-surface.cn.md
index 30e5413332d..f2a3ff34f64 100644
--- a/docs/document/content/reference/mcp/protocol-surface.cn.md
+++ b/docs/document/content/reference/mcp/protocol-surface.cn.md
@@ -201,6 +201,8 @@ Feature resources:
Completions 用于补全运行时名称、metadata identifier、算法和当前 session 中的 workflow `plan_id`。
Client 应在选择不确定的 database、schema、table、column、algorithm 或 `plan_id` 前调用
`completion/complete`,或读取最近的 MCP resource。
+当 completion 响应包含 meta `next_actions` 时,client 应先遵循这些动作,再猜测取值或切换到其他 tool。
+重试 completion 前,可通过 `resources/templates/list` 发现最近 resource 所需的 URI 变量,并补齐上下文。
## 响应与恢复
@@ -220,5 +222,7 @@ Client 应在选择不确定的 database、schema、table、column、algorithm
可恢复错误 payload 保留 `message`,并增加 `recovery` 提示。
常见恢复场景包括缺失参数、不支持的 tool/resource、非法枚举、workflow 状态错误和 SQL tool 选错。
+需要继续操作的模型可见业务 payload 会包含顶层 `summary` 和结构化 `next_actions`。
+Workflow 规划、执行、人工执行包导出和校验响应使用这些字段,引导下一次 tool call、用户补问、resource
read、completion call 或终止。
JSON-RPC 数字错误码属于 MCP 协议错误契约。
diff --git a/docs/document/content/reference/mcp/protocol-surface.en.md
b/docs/document/content/reference/mcp/protocol-surface.en.md
index d1b5371eb8f..5a581e75b31 100644
--- a/docs/document/content/reference/mcp/protocol-surface.en.md
+++ b/docs/document/content/reference/mcp/protocol-surface.en.md
@@ -201,6 +201,8 @@ Feature resources:
Completions suggest runtime names, metadata identifiers, algorithms, and
workflow `plan_id` values in the current session.
Before choosing uncertain database, schema, table, column, algorithm, or
`plan_id` values, clients should call `completion/complete` or read the nearest
MCP resource.
+When a completion response includes meta `next_actions`, clients should follow
those actions before guessing a value or switching to another tool.
+Use `resources/templates/list` to discover URI variables for the nearest
resource before retrying completion with additional context.
## Responses and recovery
@@ -220,5 +222,7 @@ Large-result payloads use:
Recoverable error payloads keep `message` and add `recovery` hints.
Common recovery cases include missing arguments, unsupported tools or
resources, invalid enum values, workflow state errors, and unsafe SQL tool
selection.
+Model-facing business payloads that require continuation include a top-level
`summary` and structured `next_actions`.
+Workflow planning, apply, manual-only export, and validation responses use
these fields to guide the next tool call, user question, resource read,
completion call, or terminal stop.
JSON-RPC numeric error codes are the MCP protocol error contract.
diff --git
a/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.cn.md
b/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.cn.md
index 4e7b370531b..70e94741cd9 100644
---
a/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.cn.md
+++
b/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.cn.md
@@ -49,6 +49,9 @@ STDIO 示例:
| `shardingsphere://capabilities` |
运行时数据库、连接目标、功能插件和副作用边界。 | 判断当前 MCP Server 可用于哪些数据库任务。 |
| `shardingsphere://databases/{database}/capabilities` | 指定运行时数据库的
SQL、事务、模式和元数据对象能力。 | 判断某个数据库的可用操作和限制。 |
+当 client 无法确定 database、schema、table、column、algorithm、storage unit 或 workflow
`plan_id` 时,应一次只针对一个参数调用 `completion/complete`。
+如果 completion 返回缺少上下文或没有候选值,应遵循返回 meta 中的 `next_actions`;这些动作通常会指向重试补全前需要读取的最近
resource 或 resource template。
+
## 资源
| 资源 URI 或模板
| 用途 |
@@ -74,6 +77,8 @@ STDIO 示例:
|
`shardingsphere://databases/{database}/schemas/{schema}/views/{view}/columns/{column}`
| 读取一个视图列的详情。 |
| `shardingsphere://workflows/{plan_id}`
| 查看当前治理变更计划、补问信息、变更产物和下一步动作。 |
+Workflow resources 和 workflow tools 会包含简短的 `summary` 以及结构化 `next_actions`,让
client 不必先读取所有嵌套字段,也能继续预览、执行、人工执行、校验或恢复。
+
## 工具
| 工具 | 用途
| 副作用 |
diff --git
a/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.en.md
b/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.en.md
index 50d5dbb1b6f..8bb1ad9960b 100644
---
a/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.en.md
+++
b/docs/document/content/user-manual/shardingsphere-mcp/developer-appendix.en.md
@@ -49,6 +49,9 @@ Replace `/path/to/apache-shardingsphere-mcp` with the actual
distribution direct
| `shardingsphere://capabilities` | Runtime databases,
connection targets, feature plugins, and side-effect boundaries. |
Determine which database tasks the current MCP Server supports. |
| `shardingsphere://databases/{database}/capabilities` | SQL, transaction,
schema, and metadata-object capabilities of the specified runtime database. |
Determine available operations and limits for one database. |
+When a client cannot choose a database, schema, table, column, algorithm,
storage unit, or workflow `plan_id`, call `completion/complete` for one
argument at a time.
+If completion reports missing context or no candidates, follow the returned
meta `next_actions`; those actions usually point to the nearest resource or
resource template to read before retrying completion.
+
## Resources
| Resource URI or template
| Purpose
|
@@ -74,6 +77,8 @@ Replace `/path/to/apache-shardingsphere-mcp` with the actual
distribution direct
|
`shardingsphere://databases/{database}/schemas/{schema}/views/{view}/columns/{column}`
| Reads one view column.
|
| `shardingsphere://workflows/{plan_id}`
| Reads the current governance change plan, clarification
questions, artifacts, and next actions.
|
+Workflow resources and workflow tools include a short `summary` plus
structured `next_actions` so clients can continue preview, apply, manual
execution, validation, or recovery without reading every nested field first.
+
## Tools
| Tool | Purpose
| Side effect
|
diff --git
a/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.cn.md
b/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.cn.md
index 9a143fae23e..5eff0046ac3 100644
---
a/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.cn.md
+++
b/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.cn.md
@@ -32,11 +32,15 @@ weight = 1
面向模型的规划响应可能包含:
+- `summary`:简短的模型可读状态摘要,说明计划需要补充信息、可以预览,或已经失败。
- `algorithm_recommendations`:根据 Proxy 可见插件目录或用户显式输入选择的候选算法。
- `property_requirements`:所选算法的必填或可选属性;缺少必填属性时,workflow 会保持在澄清状态,而不是生成不安全产物。
- `resources_to_read` 和 `next_actions`:继续 workflow 所需的资源和工具导航提示。
- `distsql_artifacts`:在当前功能插件边界内生成的可审查规则 DistSQL。
+预览、执行、人工执行包导出和校验响应也会返回 `summary` 和 `next_actions`。
+Client 应优先遵循这些字段,而不是自行猜测替代调用,或向用户询问 payload 中已经包含的信息。
+
## 变更执行选择
| 用户说法 | 用户会得到什么 | 关注点 |
diff --git
a/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.en.md
b/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.en.md
index 649c635c04c..67649b6dc65 100644
---
a/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.en.md
+++
b/docs/document/content/user-manual/shardingsphere-mcp/features/plugin-workflow.en.md
@@ -32,11 +32,15 @@ Use preview before execution when the user needs one more
confirmation step.
Model-facing planning responses may include:
+- `summary`: a short model-facing status line that tells whether the plan
needs clarification, is ready for preview, or failed.
- `algorithm_recommendations`: candidate algorithms selected from
Proxy-visible plugin catalogs or explicit user input.
- `property_requirements`: required or optional properties for the selected
algorithms. Missing required properties keep the workflow in clarification
instead of generating unsafe artifacts.
- `resources_to_read` and `next_actions`: resource and tool navigation hints
for continuing the workflow.
- `distsql_artifacts`: reviewable rule DistSQL generated inside the current
feature plugin boundary.
+Preview, apply, manual-only export, and validation responses also return
`summary` and `next_actions`.
+Clients should follow these fields before inventing a replacement call or
asking the user for information already present in the payload.
+
## Change Execution Choices
| User wording | What users receive
| Focus
|
diff --git
a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java
b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java
index 1b896b37860..9132b122e1a 100644
---
a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java
+++
b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java
@@ -62,8 +62,9 @@ public final class WorkflowApplyResponseBuilder {
final Collection<String> executedDdl,
final Collection<String> executedDistSql, final Collection<String>
skippedArtifacts,
final Map<String, Object>
manualArtifactPackage) {
String planId = snapshot.getPlanId();
- Map<String, Object> result = new LinkedHashMap<>(16, 1F);
+ Map<String, Object> result = new LinkedHashMap<>(24, 1F);
result.put("response_mode", resolveResponseMode(status,
executionMode));
+ result.put(MCPPayloadFieldNames.SUMMARY, createSummary(planId, status,
executionMode, issues, executedDdl, executedDistSql));
result.put(WorkflowFieldNames.PLAN_ID, planId);
result.put("status", status);
result.put(WorkflowFieldNames.EXECUTION_MODE, executionMode);
@@ -103,7 +104,9 @@ public final class WorkflowApplyResponseBuilder {
result.put("would_apply", false);
result.put("preview_artifacts", previewArtifacts);
result.put("review_focus",
createPreviewReviewFocus(applyExecutionMode, previewArtifacts));
- result.put("review_summary", createReviewSummary(previewArtifacts));
+ String reviewSummary = createReviewSummary(previewArtifacts);
+ result.put(MCPPayloadFieldNames.SUMMARY, reviewSummary);
+ result.put("review_summary", reviewSummary);
result.put("argument_provenance", createPreviewArgumentProvenance());
result.put(MCPPayloadFieldNames.NEXT_ACTIONS,
createPreviewNextActions(snapshot, applyExecutionMode, previewArtifacts));
return result;
@@ -119,6 +122,23 @@ public final class WorkflowApplyResponseBuilder {
return WorkflowLifecycle.STATUS_COMPLETED.equals(status) ?
MCPResponseMode.EXECUTED : MCPResponseMode.TERMINAL;
}
+ private String createSummary(final String planId, final String status,
final String executionMode, final Collection<Map<String, Object>> issues,
+ final Collection<String> executedDdl, final
Collection<String> executedDistSql) {
+ if (EXECUTION_MODE_PREVIEW.equals(executionMode)) {
+ return String.format("Workflow apply preview is ready for plan
`%s`.", planId);
+ }
+ if (WorkflowLifecycle.STATUS_COMPLETED.equals(status)) {
+ return String.format("Workflow apply completed for plan `%s` with
%d applied artifact(s).", planId, executedDdl.size() + executedDistSql.size());
+ }
+ if (WorkflowLifecycle.STATUS_AWAITING_MANUAL_EXECUTION.equals(status))
{
+ return String.format("Workflow apply exported manual artifacts for
plan `%s`; external execution is required before validation.", planId);
+ }
+ if (WorkflowLifecycle.STATUS_FAILED.equals(status)) {
+ return String.format("Workflow apply failed for plan `%s` with %d
issue(s).", planId, issues.size());
+ }
+ return String.format("Workflow apply returned status `%s` for plan
`%s`.", status, planId);
+ }
+
private List<Map<String, Object>> createPreviewArtifacts(final
Collection<WorkflowArtifactBundle.ExecutableWorkflowArtifact>
executableArtifacts) {
return
executableArtifacts.stream().map(this::createPreviewArtifact).toList();
}
diff --git
a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilderTest.java
b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilderTest.java
index 0baff20ba74..db294d199ad 100644
---
a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilderTest.java
+++
b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilderTest.java
@@ -42,6 +42,7 @@ class WorkflowApplyResponseBuilderTest {
"CREATE MASK RULE orders", true));
Map<String, Object> actual = new
WorkflowApplyResponseBuilder().buildPreviewResponse(createSnapshot("encrypt.table"),
executableArtifacts, "review-then-execute", Map.of());
assertThat(actual.get("response_mode"), is("preview"));
+ assertThat(actual.get("summary"), is("Previewed 2 workflow artifacts
with side-effect scope physical-structure, rule-metadata. Nothing has been
applied."));
assertThat(actual.get("plan_id"), is("plan-1"));
assertThat(actual.get("status"), is("preview"));
assertThat(actual.get("execution_mode"), is("preview"));
@@ -60,6 +61,7 @@ class WorkflowApplyResponseBuilderTest {
Map<String, Object> actual = new
WorkflowApplyResponseBuilder().build(createSnapshot("encrypt.table"),
WorkflowLifecycle.STATUS_COMPLETED, "review-then-execute",
List.of(), List.of(), List.of("ALTER TABLE orders ADD COLUMN
phone_mask VARCHAR(64)"), List.of("CREATE ENCRYPT RULE orders"), List.of(),
Map.of());
assertThat(actual.get("response_mode"), is("executed"));
+ assertThat(actual.get("summary"), is("Workflow apply completed for
plan `plan-1` with 2 applied artifact(s)."));
assertThat(actual.get("executed_ddl"), is(List.of("ALTER TABLE orders
ADD COLUMN phone_mask VARCHAR(64)")));
assertThat(actual.get("executed_distsql"), is(List.of("CREATE ENCRYPT
RULE orders")));
assertThat(actual.get("applied_artifacts"), is(List.of("ALTER TABLE
orders ADD COLUMN phone_mask VARCHAR(64)", "CREATE ENCRYPT RULE orders")));
@@ -75,6 +77,7 @@ class WorkflowApplyResponseBuilderTest {
Map<String, Object> actual = new
WorkflowApplyResponseBuilder().build(createSnapshot("encrypt.table"),
WorkflowLifecycle.STATUS_AWAITING_MANUAL_EXECUTION, "manual-only",
List.of(), List.of(), List.of(), List.of(), List.of(),
manualArtifactPackage);
assertThat(actual.get("response_mode"), is("manual_only"));
+ assertThat(actual.get("summary"), is("Workflow apply exported manual
artifacts for plan `plan-1`; external execution is required before
validation."));
assertThat(actual.get("manual_artifacts"),
is(List.of(manualArtifactPackage)));
Map<?, ?> actualSummary = (Map<?, ?>)
actual.get("manual_artifact_summary");
assertThat(actualSummary.get("ddl_artifact_count"), is(1));
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 4ef0313b9d1..e923bf444d1 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
@@ -221,6 +221,9 @@ tools:
enum:
- planning
- terminal
+ summary:
+ type: string
+ description: "Short model-facing workflow planning summary."
plan_id:
type: string
description: "Workflow plan identifier for
database_gateway_apply_workflow and database_gateway_validate_workflow."
@@ -318,6 +321,7 @@ tools:
additionalProperties: true
examples:
- response_mode: planning
+ summary: Workflow plan `broadcast-rule-20260606-001` for
broadcast.rule is ready for preview.
plan_id: broadcast-rule-20260606-001
status: planned
workflow_kind: broadcast.rule
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 36338f2b9ea..f54de39df40 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
@@ -274,6 +274,9 @@ tools:
enum:
- planning
- terminal
+ summary:
+ type: string
+ description: "Short model-facing workflow planning summary."
plan_id:
type: string
description: "Workflow plan identifier for
database_gateway_apply_workflow and database_gateway_validate_workflow."
@@ -410,6 +413,7 @@ tools:
description: "Typed resources the model should read when more rule
or algorithm context is useful."
examples:
- response_mode: planning
+ summary: Workflow plan `encrypt-rule-20260505-001` for encrypt.rule
is ready for preview.
plan_id: encrypt-rule-20260505-001
status: planned
workflow_kind: 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 0bbec63b449..8e84be13a2f 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
@@ -27,6 +27,7 @@ import java.util.Locale;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
class EncryptDescriptorContractTest {
@@ -35,6 +36,13 @@ class EncryptDescriptorContractTest {
assertEncryptDistSQLExampleValue(findToolDescriptor().getOutputSchema().get("examples"));
}
+ @Test
+ void assertPlanningOutputDeclaresSummary() {
+ Map<?, ?> actualOutputSchema = findToolDescriptor().getOutputSchema();
+ Map<?, ?> actualProperties = (Map<?, ?>)
actualOutputSchema.get("properties");
+ assertTrue(actualProperties.containsKey("summary"));
+ }
+
private MCPToolDescriptor findToolDescriptor() {
MCPDescriptorCatalog catalog = MCPDescriptorCatalogLoader.load();
return catalog.getProtocolDescriptors().getToolDescriptors().stream()
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 e082b3571f8..82b4d10f8b5 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
@@ -232,6 +232,9 @@ tools:
enum:
- planning
- terminal
+ summary:
+ type: string
+ description: "Short model-facing workflow planning summary."
plan_id:
type: string
description: "Workflow plan identifier for
database_gateway_apply_workflow and database_gateway_validate_workflow."
@@ -356,6 +359,7 @@ tools:
description: "Typed resources the model should read when more rule
or algorithm context is useful."
examples:
- response_mode: planning
+ summary: Workflow plan `mask-rule-20260505-001` for mask.rule is
ready for preview.
plan_id: mask-rule-20260505-001
status: planned
workflow_kind: mask.rule
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 1cbee790e3b..fe8e45a8db7 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
@@ -389,6 +389,9 @@ tools:
enum:
- planning
- terminal
+ summary:
+ type: string
+ description: "Short model-facing workflow planning summary."
plan_id:
type: string
description: "Workflow plan identifier for
database_gateway_apply_workflow and database_gateway_validate_workflow."
@@ -493,6 +496,7 @@ tools:
additionalProperties: true
examples:
- response_mode: planning
+ summary: Workflow plan `readwrite-rule-20260606-001` for
readwrite.rule is ready for preview.
plan_id: readwrite-rule-20260606-001
status: planned
workflow_kind: readwrite.rule
@@ -609,6 +613,7 @@ tools:
<<: *workflowPlanOutputSchema
examples:
- response_mode: planning
+ summary: Workflow plan `readwrite-status-20260606-001` for
readwrite.status is ready for preview.
plan_id: readwrite-status-20260606-001
status: planned
workflow_kind: readwrite.status
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 8b2c102f9e8..90631af4d88 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
@@ -468,6 +468,9 @@ tools:
enum:
- planning
- terminal
+ summary:
+ type: string
+ description: "Short model-facing workflow planning summary."
plan_id:
type: string
description: "Workflow plan identifier for
database_gateway_apply_workflow and database_gateway_validate_workflow."
@@ -577,6 +580,7 @@ tools:
additionalProperties: true
examples:
- response_mode: planning
+ summary: Workflow plan `shadow-rule-20260606-001` for shadow.rule is
ready for preview.
plan_id: shadow-rule-20260606-001
workflow_kind: shadow.rule
status: planned
@@ -657,6 +661,7 @@ tools:
<<: *workflowPlanOutputSchema
examples:
- response_mode: planning
+ summary: Workflow plan `default-shadow-algorithm-20260606-001` for
shadow.default is ready for preview.
plan_id: default-shadow-algorithm-20260606-001
workflow_kind: shadow.default
status: planned
@@ -726,6 +731,7 @@ tools:
<<: *workflowPlanOutputSchema
examples:
- response_mode: planning
+ summary: Workflow plan `shadow-algorithm-cleanup-20260606-001` for
shadow.cleanup is ready for preview.
plan_id: shadow-algorithm-cleanup-20260606-001
workflow_kind: shadow.cleanup
status: planned
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 221edec6c8e..28a0612319f 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
@@ -803,6 +803,7 @@ tools:
type: object
properties:
response_mode: {type: string, description: "Stable response mode
marker for workflow planning, or terminal when planning cannot continue.",
enum: [planning, terminal]}
+ summary: {type: string, description: "Short model-facing workflow
planning summary."}
plan_id: {type: string, description: "Workflow plan identifier for
database_gateway_apply_workflow and database_gateway_validate_workflow."}
workflow_kind: {type: string, description: "Workflow kind resolved by
the planner."}
status: {type: string, description: "Stable workflow status, such as
clarifying, planned, or failed."}
@@ -842,6 +843,7 @@ tools:
additionalProperties: true
examples:
- response_mode: planning
+ summary: Workflow plan `sharding-table-rule-20260606-001` for
sharding.table.rule is ready for preview.
plan_id: sharding-table-rule-20260606-001
workflow_kind: sharding.table.rule
status: planned
diff --git
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilder.java
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilder.java
index 8f013b469a7..1261b405d28 100644
---
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilder.java
+++
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilder.java
@@ -92,6 +92,8 @@ final class MCPGuidancePayloadBuilder {
"Stop after reporting the result rows."),
createFirstCallRoute("side_effect_sql", "call_tool
database_gateway_execute_update execution_mode=preview", "call_tool
database_gateway_execute_update execution_mode=execute",
"Execute only after preview review confirms the
intended side effect."),
+ createFirstCallRoute("complete_uncertain_argument", "call
completion/complete for one uncertain argument",
+ "follow completion meta.next_actions when context is
missing or no candidates match", "Stop after the argument is selected or the
nearest resource proves it is unavailable."),
createFirstCallRoute("recover_error", "follow top-level
next_actions", "fallback to recovery.next_actions when top-level actions are
absent",
"Ask the user only when no deterministic resource,
completion, or tool action is available."));
}
@@ -119,6 +121,8 @@ final class MCPGuidancePayloadBuilder {
result.put("sql_tool_selection", sqlToolSelection);
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("completion_rule", "Use completion/complete for one
uncertain argument at a time; when completion reports missing context, follow
meta.next_actions before guessing.");
+ result.put("resource_template_rule", "Use resources/templates/list to
discover URI variables, then read the nearest concrete resource before filling
dependent completion context.");
result.put("next_action_rule", "Use canonical next_actions fields:
type, tool_name, resource_uri, and arguments.");
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.");
@@ -183,6 +187,9 @@ final class MCPGuidancePayloadBuilder {
createCommonFlow("side_effecting_sql", List.of("call_tool
database_gateway_execute_update execution_mode=preview",
"call_tool database_gateway_execute_update
execution_mode=execute"),
"Execute only after reviewing the previewed SQL and
side-effect scope.", List.of("database_gateway_execute_update"), List.of()),
+ createCommonFlow("complete_uncertain_argument",
List.of("resources/templates/list", "call completion/complete for one argument",
+ "follow completion meta.next_actions when diagnostic
is missing_context, prefix_filtered_all_candidates, or no_candidates"),
+ "Stop when a completion value is selected or the
nearest resource proves the argument is unavailable.", List.of(), List.of()),
createCommonFlow("workflow_plan_apply_validate",
List.of("call_tool descriptor-backed feature planning tool", "call_tool
database_gateway_apply_workflow execution_mode=preview",
"call_tool database_gateway_apply_workflow
execution_mode=review-then-execute
approved_steps=<preview_artifacts.approval_step>",
"call_tool database_gateway_validate_workflow"),
diff --git
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorCatalogValidator.java
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorCatalogValidator.java
index 71cfe22ba95..51c21f2addc 100644
---
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorCatalogValidator.java
+++
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorCatalogValidator.java
@@ -206,13 +206,13 @@ public final class MCPToolDescriptorCatalogValidator {
private static void validateApplyWorkflowDescriptor(final
MCPToolDescriptor descriptor) {
MCPToolDescriptorValidationUtils.validateRequiredOutputFields(descriptor,
- List.of("response_mode", WorkflowFieldNames.PLAN_ID, "status",
WorkflowFieldNames.EXECUTION_MODE, MCPPayloadFieldNames.NEXT_ACTIONS,
"manual_artifact_summary",
- "category", "message", "secret_reference_summary"));
+ List.of("response_mode", MCPPayloadFieldNames.SUMMARY,
WorkflowFieldNames.PLAN_ID, "status", WorkflowFieldNames.EXECUTION_MODE,
MCPPayloadFieldNames.NEXT_ACTIONS,
+ "manual_artifact_summary", "category", "message",
"secret_reference_summary"));
}
private static void validateValidateWorkflowDescriptor(final
MCPToolDescriptor descriptor) {
MCPToolDescriptorValidationUtils.validateRequiredOutputFields(descriptor,
- List.of("response_mode", WorkflowFieldNames.PLAN_ID, "status",
"overall_status", "issues", MCPPayloadFieldNames.NEXT_ACTIONS));
+ List.of("response_mode", MCPPayloadFieldNames.SUMMARY,
WorkflowFieldNames.PLAN_ID, "status", "overall_status", "issues",
MCPPayloadFieldNames.NEXT_ACTIONS));
}
private static void validatePlanningWorkflowDescriptor(final
MCPToolDescriptor descriptor) {
diff --git
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtils.java
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtils.java
index 1a6c5f3b49f..6ada8bc4060 100644
---
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtils.java
+++
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtils.java
@@ -34,7 +34,7 @@ import java.util.Optional;
public final class MCPToolDescriptorValidationUtils {
private static final Collection<String>
REQUIRED_WORKFLOW_PLAN_OUTPUT_FIELDS = List.of(
- "response_mode", WorkflowFieldNames.PLAN_ID, "workflow_kind",
"status", "missing_required_inputs", "clarification_questions",
+ "response_mode", MCPPayloadFieldNames.SUMMARY,
WorkflowFieldNames.PLAN_ID, "workflow_kind", "status",
"missing_required_inputs", "clarification_questions",
"elicitation_support", "fallback_reason", "issues",
"global_steps", "current_step", "algorithm_recommendations",
"property_requirements",
"validation_strategy", "delivery_mode", "execution_mode",
"intent_inference", "argument_provenance", "review_focus",
"proxy_topology_hint",
"distsql_artifacts", MCPPayloadFieldNames.RESOURCES_TO_READ,
MCPPayloadFieldNames.NEXT_ACTIONS);
diff --git
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilder.java
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilder.java
index 92499df4c35..3cdf25d406e 100644
---
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilder.java
+++
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilder.java
@@ -19,6 +19,7 @@ package
org.apache.shardingsphere.mcp.support.workflow.service;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.mcp.support.protocol.MCPPayloadFieldNames;
import org.apache.shardingsphere.mcp.support.workflow.WorkflowPropertySource;
import
org.apache.shardingsphere.mcp.support.workflow.descriptor.WorkflowToolDescriptors;
import org.apache.shardingsphere.mcp.support.workflow.model.AlgorithmCandidate;
@@ -54,8 +55,9 @@ public final class WorkflowPlanPayloadBuilder {
* @return workflow-plan payload
*/
public static Map<String, Object> build(final WorkflowContextSnapshot
snapshot) {
- Map<String, Object> result = new LinkedHashMap<>(16, 1F);
+ Map<String, Object> result = new LinkedHashMap<>(24, 1F);
result.put("response_mode", resolveResponseMode(snapshot));
+ result.put(MCPPayloadFieldNames.SUMMARY, createSummary(snapshot));
result.put(WorkflowFieldNames.PLAN_ID, snapshot.getPlanId());
result.put("workflow_kind", snapshot.getWorkflowKind().getValue());
result.put("status", snapshot.getStatus());
@@ -75,6 +77,20 @@ public final class WorkflowPlanPayloadBuilder {
return result;
}
+ private static String createSummary(final WorkflowContextSnapshot
snapshot) {
+ String workflowKind = snapshot.getWorkflowKind().getValue();
+ if (WorkflowLifecycle.STATUS_CLARIFYING.equals(snapshot.getStatus())) {
+ return String.format("Workflow plan `%s` for %s requires
clarification before preview.", snapshot.getPlanId(), workflowKind);
+ }
+ if (WorkflowLifecycle.STATUS_PLANNED.equals(snapshot.getStatus())) {
+ return String.format("Workflow plan `%s` for %s is ready for
preview.", snapshot.getPlanId(), workflowKind);
+ }
+ if (WorkflowLifecycle.STATUS_FAILED.equals(snapshot.getStatus())) {
+ return String.format("Workflow plan `%s` for %s failed with %d
issue(s).", snapshot.getPlanId(), workflowKind, snapshot.getIssues().size());
+ }
+ return String.format("Workflow plan `%s` for %s is `%s`.",
snapshot.getPlanId(), workflowKind, snapshot.getStatus());
+ }
+
/**
* Build one rule DistSQL-only workflow-plan payload map.
*
diff --git
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupport.java
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupport.java
index 1b46bed5434..93130497533 100644
---
a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupport.java
+++
b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupport.java
@@ -17,6 +17,7 @@
package org.apache.shardingsphere.mcp.support.workflow.service;
+import org.apache.shardingsphere.mcp.support.protocol.MCPNextActionUtils;
import org.apache.shardingsphere.mcp.support.protocol.MCPPayloadFieldNames;
import org.apache.shardingsphere.mcp.support.workflow.WorkflowSessionContext;
import org.apache.shardingsphere.mcp.support.workflow.model.ValidationReport;
@@ -131,6 +132,7 @@ public final class WorkflowValidationSupport {
workflowSessionContext.persist(snapshot,
WorkflowLifecycle.STEP_VALIDATED, validationStatus);
Map<String, Object> result = new LinkedHashMap<>(16, 1F);
result.put("response_mode", "validation");
+ result.put(MCPPayloadFieldNames.SUMMARY,
createValidationSummary(snapshot, validationReport));
result.put(WorkflowFieldNames.PLAN_ID, snapshot.getPlanId());
result.put("status", validationStatus);
result.put("issues", createValidationIssues(validationReport));
@@ -194,6 +196,13 @@ public final class WorkflowValidationSupport {
return
WorkflowLifecycle.STATUS_FAILED.equals(validationReport.getOverallStatus()) ?
WorkflowLifecycle.STATUS_FAILED : WorkflowLifecycle.STATUS_VALIDATED;
}
+ private String createValidationSummary(final WorkflowContextSnapshot
snapshot, final ValidationReport validationReport) {
+ if
(WorkflowLifecycle.STATUS_FAILED.equals(validationReport.getOverallStatus())) {
+ return String.format("Workflow validation failed for plan `%s`
with %d mismatch(es).", snapshot.getPlanId(),
validationReport.getMismatches().size());
+ }
+ return String.format("Workflow validation passed for plan `%s`.",
snapshot.getPlanId());
+ }
+
private boolean isValidatableStatus(final WorkflowContextSnapshot
snapshot) {
String actualStatus = null == snapshot.getStatus() ? "" :
snapshot.getStatus();
if (WorkflowLifecycle.STATUS_VALIDATED.equalsIgnoreCase(actualStatus)
@@ -211,18 +220,27 @@ public final class WorkflowValidationSupport {
}
private Map<String, Object> createRejectedResponse(final
WorkflowContextSnapshot snapshot, final String issueCode, final String message,
final String userAction) {
- Map<String, Object> result = new LinkedHashMap<>(9, 1F);
+ Map<String, Object> result = new LinkedHashMap<>(10, 1F);
result.put("response_mode", "terminal");
+ result.put(MCPPayloadFieldNames.SUMMARY, String.format("Workflow
validation cannot run for plan `%s`.", snapshot.getPlanId()));
result.put(WorkflowFieldNames.PLAN_ID, snapshot.getPlanId());
result.put("status", WorkflowLifecycle.STATUS_FAILED);
result.put("issues", List.of(new WorkflowIssue(issueCode, "error",
"validating", message, userAction, false, Map.of()).toMap()));
result.put("overall_status", WorkflowLifecycle.STATUS_FAILED);
result.put("mismatches", List.of());
result.put("recovery_guidance", userAction);
- result.put(MCPPayloadFieldNames.NEXT_ACTIONS, List.of());
+ result.put(MCPPayloadFieldNames.NEXT_ACTIONS,
createRejectedNextActions(issueCode, userAction));
return result;
}
+ private List<Map<String, Object>> createRejectedNextActions(final String
issueCode, final String userAction) {
+ return
MCPNextActionUtils.ordered(MCPNextActionUtils.askUser(userAction,
List.of(resolveRejectedRequiredInput(issueCode))));
+ }
+
+ private String resolveRejectedRequiredInput(final String issueCode) {
+ return WorkflowIssueCode.SESSION_OWNERSHIP_MISMATCH.equals(issueCode)
? "same_mcp_session" : "validatable_workflow_state";
+ }
+
/**
* Resolve validation issue code from mismatches.
*
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 845d91d86c6..fee54f5217f 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
@@ -225,6 +225,9 @@ tools:
- manual_only
- recovery
- terminal
+ summary:
+ type: string
+ description: "Short model-facing workflow apply summary."
plan_id:
type: string
description: "Workflow plan identifier that was applied."
@@ -378,6 +381,7 @@ tools:
description: "Action order values that must complete before
this action."
examples:
- response_mode: preview
+ summary: Previewed 0 workflow artifacts. Nothing has been applied.
plan_id: encrypt-rule-20260505-001
execution_mode: preview
applied_artifacts: []
@@ -429,6 +433,9 @@ tools:
enum:
- validation
- terminal
+ summary:
+ type: string
+ description: "Short model-facing workflow validation summary."
plan_id:
type: string
description: "Workflow plan identifier that was validated."
@@ -540,6 +547,7 @@ tools:
description: "Action order values that must complete before
this action."
examples:
- response_mode: validation
+ summary: Workflow validation passed for plan
`encrypt-rule-20260505-001`.
plan_id: encrypt-rule-20260505-001
status: passed
sections: []
diff --git
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogLoaderTest.java
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogLoaderTest.java
index 89a4c989bf7..8b5ee4211a5 100644
---
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogLoaderTest.java
+++
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogLoaderTest.java
@@ -45,9 +45,9 @@ class MCPDescriptorCatalogLoaderTest {
Set<String> actualToolNames =
actual.getProtocolDescriptors().getToolDescriptors().stream().map(MCPToolDescriptor::getName).collect(Collectors.toSet());
assertToolNames(actualToolNames);
assertOutputProperties(actual, "database_gateway_apply_workflow",
Set.of(
- "response_mode", "plan_id", "execution_mode", "next_actions",
"manual_artifact_package", "manual_artifact_summary", "manual_follow_up",
"argument_provenance",
+ "response_mode", "summary", "plan_id", "execution_mode",
"next_actions", "manual_artifact_package", "manual_artifact_summary",
"manual_follow_up", "argument_provenance",
"review_summary", "review_focus", "category", "message",
"secret_reference_summary"));
- assertOutputProperties(actual, "database_gateway_validate_workflow",
Set.of("response_mode", "plan_id", "status", "recovery_guidance",
"next_actions", "sections", "mismatches"));
+ assertOutputProperties(actual, "database_gateway_validate_workflow",
Set.of("response_mode", "summary", "plan_id", "status", "recovery_guidance",
"next_actions", "sections", "mismatches"));
assertPublicToolAnnotations(actual);
assertPlanningToolAnnotations(actual);
assertResourceDescriptor(actual);
diff --git
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogValidatorTest.java
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogValidatorTest.java
index dccc391cfe2..d7d97a39f31 100644
---
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogValidatorTest.java
+++
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogValidatorTest.java
@@ -301,9 +301,10 @@ class MCPDescriptorCatalogValidatorTest {
private Map<String, Object> createWorkflowPlanOutputSchema() {
Map<String, Object> properties = new LinkedHashMap<>();
for (String each : List.of(
- "response_mode", WorkflowFieldNames.PLAN_ID, "workflow_kind",
"status", "missing_required_inputs", "clarification_questions",
"elicitation_support",
- "fallback_reason", "issues", "global_steps", "current_step",
"algorithm_recommendations", "property_requirements", "validation_strategy",
"delivery_mode",
- "execution_mode", "intent_inference", "argument_provenance",
"review_focus", "proxy_topology_hint", "distsql_artifacts",
MCPPayloadFieldNames.RESOURCES_TO_READ)) {
+ "response_mode", MCPPayloadFieldNames.SUMMARY,
WorkflowFieldNames.PLAN_ID, "workflow_kind", "status",
"missing_required_inputs", "clarification_questions",
+ "elicitation_support", "fallback_reason", "issues",
"global_steps", "current_step", "algorithm_recommendations",
"property_requirements", "validation_strategy",
+ "delivery_mode", "execution_mode", "intent_inference",
"argument_provenance", "review_focus", "proxy_topology_hint",
"distsql_artifacts",
+ MCPPayloadFieldNames.RESOURCES_TO_READ)) {
properties.put(each, Map.of("type", "object", "description",
"Workflow plan field."));
}
properties.put(MCPPayloadFieldNames.NEXT_ACTIONS,
createNextActionsSchema());
diff --git
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilderTest.java
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilderTest.java
index be5ee710d52..bbf10e2a823 100644
---
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilderTest.java
+++
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPGuidancePayloadBuilderTest.java
@@ -53,6 +53,8 @@ class MCPGuidancePayloadBuilderTest {
assertFalse(actual.containsKey("safe_first_resource"));
Map<?, ?> actualMetadataRoute =
findByKey(castToRouteList(actual.get("first_call_routes")), "intent",
"inspect_metadata");
assertThat(actualMetadataRoute.get("first_action"), is("read_resource
shardingsphere://databases"));
+ Map<?, ?> actualCompletionRoute =
findByKey(castToRouteList(actual.get("first_call_routes")), "intent",
"complete_uncertain_argument");
+ assertThat(actualCompletionRoute.get("first_action"), is("call
completion/complete for one uncertain argument"));
Map<?, ?> actualRecoveryRoute =
findByKey(castToRouteList(actual.get("first_call_routes")), "intent",
"recover_error");
assertThat(actualRecoveryRoute.get("first_action"), is("follow
top-level next_actions"));
assertThat(((Map<?, ?>) actual.get("preflight_rule")).get("tool"),
is("database_gateway_validate_runtime_database"));
@@ -76,6 +78,10 @@ class MCPGuidancePayloadBuilderTest {
assertTrue(String.valueOf(actual.get("preflight_rule")).contains("database_gateway_validate_runtime_database"));
assertThat(castToMap(actual.get("sql_tool_selection")).keySet().stream().toList(),
is(List.of("read_only", "side_effecting")));
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("completion_rule"),
+ is("Use completion/complete for one uncertain argument at a
time; when completion reports missing context, follow meta.next_actions before
guessing."));
+ assertThat(actual.get("resource_template_rule"),
+ is("Use resources/templates/list to discover URI variables,
then read the nearest concrete resource before filling dependent completion
context."));
assertThat(actual.get("detail_resource_rule"), is("Use resource
descriptors, outputSchema, and returned payload keys before assuming detail
fields."));
}
@@ -97,10 +103,12 @@ class MCPGuidancePayloadBuilderTest {
List<Map<String, Object>> actual = builder.createCommonFlows();
Map<?, ?> actualInspectMetadata = findByKey(actual, "flow_id",
"inspect_metadata");
assertTrue(((Collection<?>)
actualInspectMetadata.get("steps")).contains("resources/list"));
- Map<?, ?> actualSideEffectingSql = findByKey(actual, "flow_id",
"side_effecting_sql");
Map<?, ?> actualValidateRuntimeDatabase = findByKey(actual, "flow_id",
"validate_runtime_database");
assertTrue(((Collection<?>)
actualValidateRuntimeDatabase.get("steps")).contains("call_tool
database_gateway_validate_runtime_database"));
assertThat(actualValidateRuntimeDatabase.get("referenced_tools"),
is(List.of("database_gateway_validate_runtime_database")));
+ Map<?, ?> actualCompleteArgument = findByKey(actual, "flow_id",
"complete_uncertain_argument");
+ assertTrue(((Collection<?>)
actualCompleteArgument.get("steps")).contains("call completion/complete for one
argument"));
+ Map<?, ?> actualSideEffectingSql = findByKey(actual, "flow_id",
"side_effecting_sql");
assertThat(actualSideEffectingSql.get("referenced_tools"),
is(List.of("database_gateway_execute_update")));
assertTrue(((Collection<?>)
actualSideEffectingSql.get("steps")).contains("call_tool
database_gateway_execute_update execution_mode=preview"));
Map<?, ?> actualWorkflow = findByKey(actual, "flow_id",
"workflow_plan_apply_validate");
diff --git
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtilsTest.java
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtilsTest.java
index 1af04338ea6..fd87ac5e663 100644
---
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtilsTest.java
+++
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolDescriptorValidationUtilsTest.java
@@ -38,7 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
class MCPToolDescriptorValidationUtilsTest {
private static final Collection<String> WORKFLOW_PLAN_OUTPUT_FIELDS =
List.of(
- "response_mode", WorkflowFieldNames.PLAN_ID, "workflow_kind",
"status", "missing_required_inputs", "clarification_questions",
+ "response_mode", MCPPayloadFieldNames.SUMMARY,
WorkflowFieldNames.PLAN_ID, "workflow_kind", "status",
"missing_required_inputs", "clarification_questions",
"elicitation_support", "fallback_reason", "issues",
"global_steps", "current_step", "algorithm_recommendations",
"property_requirements",
"validation_strategy", "delivery_mode", "execution_mode",
"intent_inference", "argument_provenance", "review_focus",
"proxy_topology_hint",
"distsql_artifacts", MCPPayloadFieldNames.RESOURCES_TO_READ,
MCPPayloadFieldNames.NEXT_ACTIONS);
diff --git
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
index 2a3cdc0d63b..508c91dca9c 100644
---
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
+++
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowPlanPayloadBuilderTest.java
@@ -73,6 +73,7 @@ class WorkflowPlanPayloadBuilderTest {
snapshot.setInteractionPlan(interactionPlan);
Map<String, Object> actual =
WorkflowPlanPayloadBuilder.build(snapshot);
assertThat(actual.get("response_mode"), is("planning"));
+ assertThat(actual.get("summary"), is("Workflow plan `plan-1` for
encrypt.rule requires clarification before preview."));
assertThat(actual.get("plan_id"), is("plan-1"));
assertThat(actual.get("workflow_kind"), is("encrypt.rule"));
assertThat(((Map<?, ?>)
actual.get("intent_inference")).get("operation_type"), is("create"));
@@ -157,6 +158,7 @@ class WorkflowPlanPayloadBuilderTest {
snapshot.setRequest(request);
snapshot.setInteractionPlan(InteractionPlan.create("plan-1", request,
"Mask workflow plan.", List.of("Review"), List.of("rules")));
Map<String, Object> actual =
WorkflowPlanPayloadBuilder.build(snapshot);
+ assertThat(actual.get("summary"), is("Workflow plan `plan-1` for
mask.rule is ready for preview."));
List<?> actualResourcesToRead = (List<?>)
actual.get("resources_to_read");
List<String> actualResourceUris =
extractResourceUris(actualResourcesToRead);
assertTrue(actualResourceUris.contains("shardingsphere://features/mask/algorithms"));
@@ -335,6 +337,7 @@ class WorkflowPlanPayloadBuilderTest {
Map<String, Object> actual =
WorkflowPlanPayloadBuilder.build(snapshot);
Map<?, ?> actualNextAction = (Map<?, ?>) ((List<?>)
actual.get("next_actions")).getFirst();
assertThat(actual.get("response_mode"), is("terminal"));
+ assertThat(actual.get("summary"), is("Workflow plan `plan-1` for
encrypt.rule failed with 0 issue(s)."));
assertThat(actualNextAction.get("type"), is("tool_call"));
assertThat(actualNextAction.get("tool_name"),
is("database_gateway_plan_encrypt_rule"));
}
diff --git
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupportTest.java
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupportTest.java
index 2aeee3790bc..341fcfc7737 100644
---
a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupportTest.java
+++
b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowValidationSupportTest.java
@@ -49,9 +49,11 @@ class WorkflowValidationSupportTest {
snapshot.setStatus("executed");
Map<String, Object> actualResult =
validationSupport.checkValidatePreconditions("session-2", snapshot);
assertThat(actualResult.get("status"), is("failed"));
+ assertThat(actualResult.get("summary"), is("Workflow validation cannot
run for plan `plan-1`."));
assertThat(actualResult.get("plan_id"), is("plan-1"));
assertThat(actualResult.get("recovery_guidance"), is("Continue the
workflow from the same session that created the plan."));
assertThat(((Map<?, ?>) ((List<?>)
actualResult.get("issues")).get(0)).get("code"),
is(WorkflowIssueCode.SESSION_OWNERSHIP_MISMATCH));
+ assertThat(((Map<?, ?>) ((List<?>)
actualResult.get("next_actions")).getFirst()).get("required_inputs"),
is(List.of("same_mcp_session")));
}
@Test
@@ -65,6 +67,7 @@ class WorkflowValidationSupportTest {
assertThat(actualResult.get("plan_id"), is("plan-1"));
assertThat(actualResult.get("recovery_guidance"), is("Execute the
workflow first or continue from a validatable status."));
assertThat(((Map<?, ?>) ((List<?>)
actualResult.get("issues")).get(0)).get("code"),
is(WorkflowIssueCode.WORKFLOW_STATUS_INVALID));
+ assertThat(((Map<?, ?>) ((List<?>)
actualResult.get("next_actions")).getFirst()).get("required_inputs"),
is(List.of("validatable_workflow_state")));
}
@Test
@@ -153,6 +156,7 @@ class WorkflowValidationSupportTest {
workflowSessionContext.save(snapshot);
Map<String, Object> actualResult =
validationSupport.finalizeValidation(workflowSessionContext, snapshot,
validationReport);
assertThat(actualResult.get("response_mode"), is("validation"));
+ assertThat(actualResult.get("summary"), is("Workflow validation passed
for plan `plan-1`."));
assertThat(actualResult.get("status"), is("validated"));
assertThat(actualResult.get("plan_id"), is("plan-1"));
assertThat(actualResult.get("recovery_guidance"), is(""));
@@ -175,6 +179,7 @@ class WorkflowValidationSupportTest {
workflowSessionContext.save(snapshot);
Map<String, Object> actualResult =
validationSupport.finalizeValidation(workflowSessionContext, snapshot,
validationReport);
assertThat(actualResult.get("response_mode"), is("validation"));
+ assertThat(actualResult.get("summary"), is("Workflow validation failed
for plan `plan-1` with 1 mismatch(es)."));
assertThat(((Map<?, ?>) ((List<?>)
actualResult.get("issues")).get(0)).get("code"),
is(WorkflowIssueCode.SQL_EXECUTABILITY_FAILED));
assertThat(actualResult.get("status"), is("failed"));
assertThat(actualResult.get("recovery_guidance"), is("Inspect
mismatches, adjust the plan or runtime state, then run
database_gateway_validate_workflow again."));
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 7a70c2e7334..fb162f71163 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
@@ -87,6 +87,9 @@ tools:
response_mode:
type: string
description: "Machine-readable response mode for planning or
terminal workflow states."
+ summary:
+ type: string
+ description: "Short model-facing workflow planning summary."
plan_id:
type: string
description: "Workflow plan identifier for
database_gateway_apply_workflow and database_gateway_validate_workflow."
@@ -170,6 +173,7 @@ tools:
description: "Why the model should take this action."
examples:
- response_mode: planning
+ summary: Workflow plan `encrypt-rule-20260505-001` for encrypt.rule
is ready for preview.
plan_id: encrypt-rule-20260505-001
workflow_kind: encrypt.rule
status: planned