You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2026/07/24 10:35:24 UTC

(shardingsphere) branch master updated: Refactor MCP contracts and E2E runtime setup (#39235)

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 56b4594a381 Refactor MCP contracts and E2E runtime setup (#39235)
56b4594a381 is described below

commit 56b4594a3812351b7736a5a3b8ca82ddba0b446e
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Fri Jul 24 18:35:17 2026 +0800

    Refactor MCP contracts and E2E runtime setup (#39235)
    
    * Refactor MCP contracts and E2E runtime setup
    
    - centralize descriptor-driven metadata and simplify runtime configuration
    - preserve algorithm discovery confidence across compatibility fallbacks
    - remove unused runtime metadata and legacy test wrappers
    - discover packaged and Docker E2E ports at runtime
    
    * Refactor MCP contracts and E2E runtime setup
    
    - centralize descriptor-driven metadata and simplify runtime configuration
    - preserve algorithm discovery confidence across compatibility fallbacks
    - remove unused runtime metadata and legacy test wrappers
    - discover packaged and Docker E2E ports at runtime
---
 .../content/reference/mcp/protocol-surface.cn.md   |  2 +-
 .../content/reference/mcp/protocol-surface.en.md   |  2 +-
 .../yaml/config/YamlMCPLaunchConfiguration.java    |  3 +-
 ...YamlRuntimeDatabaseConfigurationProperties.java | 40 ------------
 .../YamlRuntimeDatabaseConfigurationsSwapper.java  | 51 +++------------
 ...YamlRuntimeDatabaseConfigurationsValidator.java | 63 ++++++-------------
 .../config/MCPLaunchConfigurationTest.java         | 14 +++--
 .../YamlMCPLaunchConfigurationSwapperTest.java     |  8 +--
 ...mlRuntimeDatabaseConfigurationsSwapperTest.java | 41 +++++-------
 .../metadata/MetadataResourceResponseFactory.java  |  6 +-
 .../core/workflow/WorkflowExecutionService.java    |  3 +-
 .../core/workflow/WorkflowProxyQueryService.java   |  3 +-
 .../mcp-descriptors/mcp-descriptor-core.yaml       |  7 ---
 .../MetadataResourceResponseFactoryTest.java       | 10 ++-
 .../MetadataSearchResourceUriFactoryTest.java      | 54 ++++++++++++++++
 .../EncryptAlgorithmCompletionHandler.java         |  2 +-
 .../resource/handler/EncryptAlgorithmsHandler.java |  2 +-
 .../EncryptAlgorithmRecommendationService.java     | 53 ++++++++--------
 .../tool/service/EncryptRuleInspectionService.java | 14 +++--
 .../service/EncryptWorkflowPlanningService.java    |  3 +-
 .../handler/EncryptAlgorithmsHandlerTest.java      |  3 +-
 .../EncryptAlgorithmRecommendationServiceTest.java | 72 ++++++++++++++++-----
 .../service/EncryptRuleInspectionServiceTest.java  | 31 ++++-----
 .../EncryptWorkflowPlanningServiceTest.java        |  9 +--
 .../completion/MaskAlgorithmCompletionHandler.java |  2 +-
 .../resource/handler/MaskAlgorithmsHandler.java    |  2 +-
 .../MaskAlgorithmRecommendationService.java        |  9 +--
 .../tool/service/MaskRuleInspectionService.java    | 12 ++--
 .../tool/service/MaskWorkflowPlanningService.java  |  3 +-
 .../handler/MaskAlgorithmsHandlerTest.java         |  3 +-
 .../MaskAlgorithmRecommendationServiceTest.java    | 27 ++++++--
 .../service/MaskRuleInspectionServiceTest.java     | 24 ++++---
 .../service/MaskWorkflowPlanningServiceTest.java   |  7 ++-
 .../mcp-descriptors/mcp-descriptor-shadow.yaml     |  2 +-
 .../shadow/ShadowDescriptorContractTest.java       | 11 ++++
 .../service/ShardingWorkflowValidationService.java |  2 +-
 .../mcp-descriptors/mcp-descriptor-sharding.yaml   | 23 ++++---
 .../sharding/ShardingDescriptorContractTest.java   | 12 ++++
 .../handler/ShardingWorkflowToolHandlersTest.java  | 11 +++-
 .../descriptor/MCPDescriptorCatalogIndex.java      | 26 ++++++++
 .../MCPDescriptorCatalogYamlSwapper.java           |  2 +-
 .../descriptor/MCPDescriptorYamlKeyValidator.java  |  2 +-
 .../descriptor/MCPGuidancePayloadBuilder.java      | 23 +++----
 .../MCPResourceNavigationPayloadBuilder.java       | 20 +-----
 .../MCPToolDescriptorCatalogValidator.java         | 13 +---
 .../descriptor/MCPToolRuntimeDescriptor.java       |  4 --
 .../yaml/YamlMCPToolRuntimeDescriptor.java         |  5 --
 .../protocol/MCPModelFacingPayloadContract.java    | 20 +++---
 .../workflow/model/SecretReferenceValue.java       |  3 +-
 .../workflow/model/WorkflowContextSnapshot.java    |  6 +-
 .../service/WorkflowArtifactMaskUtils.java         |  3 +-
 .../WorkflowGuidanceResourceHintProvider.java      |  9 +--
 .../mcp-descriptors/mcp-descriptor-support.yaml    |  3 -
 .../descriptor/MCPDescriptorCatalogIndexTest.java  | 16 +++--
 .../MCPDescriptorCatalogValidatorTest.java         | 41 ++++--------
 .../MCPResourceNavigationPayloadBuilderTest.java   |  7 +--
 .../MCPShardingSphereDescriptorCatalogTest.java    |  2 +-
 .../MCPModelFacingPayloadContractTest.java         |  6 +-
 .../distribution/DockerImageHttpRuntime.java       | 73 ++++++++++++++++++----
 .../distribution/DockerImageHttpRuntimeTest.java   | 58 +++++++++++++++++
 .../PackagedDistributionHttpRuntime.java           | 32 +++++++++-
 .../PackagedDistributionHttpRuntimeTest.java       | 44 +++++++++++++
 .../PackagedDistributionTestSupport.java           | 31 +++------
 .../PackagedDistributionTestSupportTest.java       |  5 +-
 .../runtime/MySQLRuntimeDockerSupportTest.java     | 53 ++++++++++++++++
 .../support/runtime/MySQLRuntimeTestSupport.java   | 19 ------
 .../runtime/MySQLRuntimeTestSupportTest.java       | 26 --------
 67 files changed, 690 insertions(+), 508 deletions(-)

diff --git a/docs/document/content/reference/mcp/protocol-surface.cn.md b/docs/document/content/reference/mcp/protocol-surface.cn.md
index 6601b6278f5..f3a9aa0d490 100644
--- a/docs/document/content/reference/mcp/protocol-surface.cn.md
+++ b/docs/document/content/reference/mcp/protocol-surface.cn.md
@@ -223,7 +223,7 @@ Client 应在选择不确定的 database、schema、table、column、storage uni
 - `items`
 - `count`
 - `continuation_mode`
-- 存在后续结果时的 `next_page_token`
+- 支持偏移量续页时的 `has_more` 和 `next_offset`
 
 大结果 payload 会使用:
 
diff --git a/docs/document/content/reference/mcp/protocol-surface.en.md b/docs/document/content/reference/mcp/protocol-surface.en.md
index 018e34dc8da..d50c0b24e5a 100644
--- a/docs/document/content/reference/mcp/protocol-surface.en.md
+++ b/docs/document/content/reference/mcp/protocol-surface.en.md
@@ -223,7 +223,7 @@ List-shaped business payloads usually contain:
 - `items`
 - `count`
 - `continuation_mode`
-- `next_page_token` when continuation is available
+- `has_more` and `next_offset` when offset continuation is available
 
 Large-result payloads use:
 
diff --git a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/config/YamlMCPLaunchConfiguration.java b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/config/YamlMCPLaunchConfiguration.java
index d31a522d2c6..df16e0b1113 100644
--- a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/config/YamlMCPLaunchConfiguration.java
+++ b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/config/YamlMCPLaunchConfiguration.java
@@ -40,6 +40,7 @@ public final class YamlMCPLaunchConfiguration implements YamlConfiguration {
     private YamlMCPTransportConfiguration transport;
     
     @NotNull(message = "is required")
+    @Valid
     @ValidYamlRuntimeDatabaseConfigurations
-    private Map<String, Map<String, Object>> runtimeDatabases;
+    private Map<String, YamlRuntimeDatabaseConfiguration> runtimeDatabases;
 }
diff --git a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/config/YamlRuntimeDatabaseConfigurationProperties.java b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/config/YamlRuntimeDatabaseConfigurationProperties.java
deleted file mode 100644
index 1cd76aba303..00000000000
--- a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/config/YamlRuntimeDatabaseConfigurationProperties.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shardingsphere.mcp.bootstrap.config.yaml.config;
-
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-
-import java.util.Set;
-
-/**
- * YAML runtime database configuration properties.
- */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class YamlRuntimeDatabaseConfigurationProperties {
-    
-    public static final String JDBC_URL = "jdbcUrl";
-    
-    public static final String USERNAME = "username";
-    
-    public static final String PASSWORD = "password";
-    
-    public static final String DRIVER_CLASS_NAME = "driverClassName";
-    
-    public static final Set<String> SUPPORTED_PROPERTIES = Set.of(JDBC_URL, USERNAME, PASSWORD, DRIVER_CLASS_NAME);
-}
diff --git a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapper.java b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapper.java
index 61058af308c..c0b2fb91f96 100644
--- a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapper.java
+++ b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapper.java
@@ -19,7 +19,6 @@ package org.apache.shardingsphere.mcp.bootstrap.config.yaml.swapper;
 
 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlRuntimeDatabaseConfiguration;
-import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlRuntimeDatabaseConfigurationProperties;
 import org.apache.shardingsphere.mcp.support.database.metadata.jdbc.RuntimeDatabaseConfiguration;
 
 import java.util.Collections;
@@ -40,14 +39,14 @@ public final class YamlRuntimeDatabaseConfigurationsSwapper {
      * @param yamlRuntimeConfiguration YAML runtime configuration
      * @return runtime configuration object
      */
-    public Map<String, RuntimeDatabaseConfiguration> swapToObject(final Map<String, Map<String, Object>> yamlRuntimeConfiguration) {
+    public Map<String, RuntimeDatabaseConfiguration> swapToObject(final Map<String, YamlRuntimeDatabaseConfiguration> yamlRuntimeConfiguration) {
         if (null == yamlRuntimeConfiguration) {
             return Collections.emptyMap();
         }
         Map<String, RuntimeDatabaseConfiguration> result = new LinkedHashMap<>(yamlRuntimeConfiguration.size(), 1F);
-        for (Entry<String, Map<String, Object>> entry : yamlRuntimeConfiguration.entrySet()) {
-            validateYamlRuntimeDatabaseConfiguration(entry.getValue());
-            result.put(entry.getKey(), runtimeDatabaseConfigSwapper.swapToObject(createYamlRuntimeDatabaseConfiguration(entry.getValue())));
+        for (Entry<String, YamlRuntimeDatabaseConfiguration> entry : yamlRuntimeConfiguration.entrySet()) {
+            ShardingSpherePreconditions.checkNotNull(entry.getValue(), () -> new IllegalArgumentException("MCP runtime database configuration cannot be null."));
+            result.put(entry.getKey(), runtimeDatabaseConfigSwapper.swapToObject(entry.getValue()));
         }
         return result;
     }
@@ -58,48 +57,12 @@ public final class YamlRuntimeDatabaseConfigurationsSwapper {
      * @param runtimeConfiguration runtime configuration
      * @return YAML runtime configuration
      */
-    public Map<String, Map<String, Object>> swapToYamlConfiguration(final Map<String, RuntimeDatabaseConfiguration> runtimeConfiguration) {
-        Map<String, Map<String, Object>> result = new LinkedHashMap<>(runtimeConfiguration.size(), 1F);
+    public Map<String, YamlRuntimeDatabaseConfiguration> swapToYamlConfiguration(final Map<String, RuntimeDatabaseConfiguration> runtimeConfiguration) {
+        Map<String, YamlRuntimeDatabaseConfiguration> result = new LinkedHashMap<>(runtimeConfiguration.size(), 1F);
         for (Entry<String, RuntimeDatabaseConfiguration> entry : runtimeConfiguration.entrySet()) {
             ShardingSpherePreconditions.checkNotNull(entry.getValue(), () -> new IllegalArgumentException("Runtime database configuration cannot be null."));
-            result.put(entry.getKey(), createYamlRuntimeDatabaseConfiguration(runtimeDatabaseConfigSwapper.swapToYamlConfiguration(entry.getValue())));
+            result.put(entry.getKey(), runtimeDatabaseConfigSwapper.swapToYamlConfiguration(entry.getValue()));
         }
         return result;
     }
-    
-    private YamlRuntimeDatabaseConfiguration createYamlRuntimeDatabaseConfiguration(final Map<String, Object> yamlProperties) {
-        if (null == yamlProperties) {
-            return null;
-        }
-        YamlRuntimeDatabaseConfiguration result = new YamlRuntimeDatabaseConfiguration();
-        result.setJdbcUrl(getYamlText(yamlProperties, YamlRuntimeDatabaseConfigurationProperties.JDBC_URL));
-        result.setUsername(getYamlText(yamlProperties, YamlRuntimeDatabaseConfigurationProperties.USERNAME));
-        result.setPassword(getYamlText(yamlProperties, YamlRuntimeDatabaseConfigurationProperties.PASSWORD));
-        result.setDriverClassName(getYamlText(yamlProperties, YamlRuntimeDatabaseConfigurationProperties.DRIVER_CLASS_NAME));
-        return result;
-    }
-    
-    private Map<String, Object> createYamlRuntimeDatabaseConfiguration(final YamlRuntimeDatabaseConfiguration yamlRuntimeDatabaseConfig) {
-        Map<String, Object> result = new LinkedHashMap<>(YamlRuntimeDatabaseConfigurationProperties.SUPPORTED_PROPERTIES.size(), 1F);
-        result.put(YamlRuntimeDatabaseConfigurationProperties.JDBC_URL, yamlRuntimeDatabaseConfig.getJdbcUrl());
-        result.put(YamlRuntimeDatabaseConfigurationProperties.USERNAME, yamlRuntimeDatabaseConfig.getUsername());
-        result.put(YamlRuntimeDatabaseConfigurationProperties.PASSWORD, yamlRuntimeDatabaseConfig.getPassword());
-        result.put(YamlRuntimeDatabaseConfigurationProperties.DRIVER_CLASS_NAME, yamlRuntimeDatabaseConfig.getDriverClassName());
-        return result;
-    }
-    
-    private void validateYamlRuntimeDatabaseConfiguration(final Map<String, Object> yamlProperties) {
-        if (null == yamlProperties) {
-            return;
-        }
-        for (String each : yamlProperties.keySet()) {
-            ShardingSpherePreconditions.checkState(YamlRuntimeDatabaseConfigurationProperties.SUPPORTED_PROPERTIES.contains(each),
-                    () -> new IllegalArgumentException(String.format("Unsupported runtime database property `%s`.", each)));
-        }
-    }
-    
-    private String getYamlText(final Map<String, Object> yamlProperties, final String key) {
-        Object result = yamlProperties.get(key);
-        return null == result ? null : result.toString();
-    }
 }
diff --git a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/validator/YamlRuntimeDatabaseConfigurationsValidator.java b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/validator/YamlRuntimeDatabaseConfigurationsValidator.java
index e699e3ae613..8f312bd2782 100644
--- a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/validator/YamlRuntimeDatabaseConfigurationsValidator.java
+++ b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/validator/YamlRuntimeDatabaseConfigurationsValidator.java
@@ -17,7 +17,7 @@
 
 package org.apache.shardingsphere.mcp.bootstrap.config.yaml.validator;
 
-import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlRuntimeDatabaseConfigurationProperties;
+import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlRuntimeDatabaseConfiguration;
 
 import javax.validation.ConstraintValidator;
 import javax.validation.ConstraintValidatorContext;
@@ -27,21 +27,21 @@ import java.util.Map.Entry;
 /**
  * YAML runtime database configurations validator.
  */
-public final class YamlRuntimeDatabaseConfigurationsValidator implements ConstraintValidator<ValidYamlRuntimeDatabaseConfigurations, Map<String, Map<String, Object>>> {
+public final class YamlRuntimeDatabaseConfigurationsValidator implements ConstraintValidator<ValidYamlRuntimeDatabaseConfigurations, Map<String, YamlRuntimeDatabaseConfiguration>> {
     
     @Override
-    public boolean isValid(final Map<String, Map<String, Object>> value, final ConstraintValidatorContext context) {
+    public boolean isValid(final Map<String, YamlRuntimeDatabaseConfiguration> value, final ConstraintValidatorContext context) {
         if (null == value) {
             return true;
         }
         boolean result = true;
-        for (Entry<String, Map<String, Object>> entry : value.entrySet()) {
+        for (Entry<String, YamlRuntimeDatabaseConfiguration> entry : value.entrySet()) {
             result = validateRuntimeDatabase(entry, context) && result;
         }
         return result;
     }
     
-    private boolean validateRuntimeDatabase(final Entry<String, Map<String, Object>> databaseEntry, final ConstraintValidatorContext context) {
+    private boolean validateRuntimeDatabase(final Entry<String, YamlRuntimeDatabaseConfiguration> databaseEntry, final ConstraintValidatorContext context) {
         if (isPlaceholder(databaseEntry.getKey())) {
             addViolation(context, String.format("contains placeholder database name `%s`", databaseEntry.getKey()));
             return false;
@@ -50,57 +50,30 @@ public final class YamlRuntimeDatabaseConfigurationsValidator implements Constra
             addViolation(context, String.format("contains null configuration for database `%s`", databaseEntry.getKey()));
             return false;
         }
-        return validateSupportedProperties(databaseEntry, context) && validateRequiredProperties(databaseEntry, context) && validateNoPlaceholders(databaseEntry, context);
+        return validateNoPlaceholders(databaseEntry, context);
     }
     
-    private boolean validateSupportedProperties(final Entry<String, Map<String, Object>> databaseEntry, final ConstraintValidatorContext context) {
-        boolean result = true;
-        for (String each : databaseEntry.getValue().keySet()) {
-            if (!YamlRuntimeDatabaseConfigurationProperties.SUPPORTED_PROPERTIES.contains(each)) {
-                addViolation(context, String.format("contains unsupported property `%s` for database `%s`", each, databaseEntry.getKey()));
-                result = false;
-            }
-        }
-        return result;
-    }
-    
-    private boolean validateRequiredProperties(final Entry<String, Map<String, Object>> databaseEntry, final ConstraintValidatorContext context) {
-        boolean result = validateRequiredText(databaseEntry, YamlRuntimeDatabaseConfigurationProperties.JDBC_URL, context);
-        result = validateRequiredText(databaseEntry, YamlRuntimeDatabaseConfigurationProperties.USERNAME, context) && result;
-        return validateRequiredText(databaseEntry, YamlRuntimeDatabaseConfigurationProperties.DRIVER_CLASS_NAME, context) && result;
-    }
-    
-    private boolean validateRequiredText(final Entry<String, Map<String, Object>> databaseEntry, final String key, final ConstraintValidatorContext context) {
-        Object value = databaseEntry.getValue().get(key);
-        if (null != value && !value.toString().isBlank()) {
-            return true;
-        }
-        addViolation(context, String.format("contains database `%s` property `%s` is required", databaseEntry.getKey(), key));
-        return false;
-    }
-    
-    private boolean validateNoPlaceholders(final Entry<String, Map<String, Object>> databaseEntry, final ConstraintValidatorContext context) {
-        boolean result = validateNoPlaceholder(databaseEntry, YamlRuntimeDatabaseConfigurationProperties.JDBC_URL, context);
-        result = validateNoPlaceholder(databaseEntry, YamlRuntimeDatabaseConfigurationProperties.USERNAME, context) && result;
-        result = validateNoPlaceholder(databaseEntry, YamlRuntimeDatabaseConfigurationProperties.DRIVER_CLASS_NAME, context) && result;
-        return validateNoPasswordPlaceholder(databaseEntry, context) && result;
+    private boolean validateNoPlaceholders(final Entry<String, YamlRuntimeDatabaseConfiguration> databaseEntry, final ConstraintValidatorContext context) {
+        YamlRuntimeDatabaseConfiguration config = databaseEntry.getValue();
+        boolean result = validateNoPlaceholder(databaseEntry.getKey(), "jdbcUrl", config.getJdbcUrl(), context);
+        result = validateNoPlaceholder(databaseEntry.getKey(), "username", config.getUsername(), context) && result;
+        result = validateNoPlaceholder(databaseEntry.getKey(), "driverClassName", config.getDriverClassName(), context) && result;
+        return validateNoPasswordPlaceholder(databaseEntry.getKey(), config.getPassword(), context) && result;
     }
     
-    private boolean validateNoPlaceholder(final Entry<String, Map<String, Object>> databaseEntry, final String key, final ConstraintValidatorContext context) {
-        Object value = databaseEntry.getValue().get(key);
-        if (null == value || !isPlaceholder(value.toString())) {
+    private boolean validateNoPlaceholder(final String databaseName, final String propertyName, final String value, final ConstraintValidatorContext context) {
+        if (null == value || !isPlaceholder(value)) {
             return true;
         }
-        addViolation(context, String.format("contains placeholder database `%s` property `%s`", databaseEntry.getKey(), key));
+        addViolation(context, String.format("contains placeholder database `%s` property `%s`", databaseName, propertyName));
         return false;
     }
     
-    private boolean validateNoPasswordPlaceholder(final Entry<String, Map<String, Object>> databaseEntry, final ConstraintValidatorContext context) {
-        Object value = databaseEntry.getValue().get(YamlRuntimeDatabaseConfigurationProperties.PASSWORD);
-        if (null == value || !isStandalonePlaceholder(value.toString())) {
+    private boolean validateNoPasswordPlaceholder(final String databaseName, final String value, final ConstraintValidatorContext context) {
+        if (null == value || !isStandalonePlaceholder(value)) {
             return true;
         }
-        addViolation(context, String.format("contains placeholder database `%s` property `%s`", databaseEntry.getKey(), YamlRuntimeDatabaseConfigurationProperties.PASSWORD));
+        addViolation(context, String.format("contains placeholder database `%s` property `password`", databaseName));
         return false;
     }
     
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/MCPLaunchConfigurationTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/MCPLaunchConfigurationTest.java
index 2710009f62d..f7778fe2b50 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/MCPLaunchConfigurationTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/MCPLaunchConfigurationTest.java
@@ -21,6 +21,7 @@ import org.apache.shardingsphere.mcp.api.transport.MCPTransportType;
 import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlHttpTransportConfiguration;
 import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlMCPLaunchConfiguration;
 import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlMCPTransportConfiguration;
+import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlRuntimeDatabaseConfiguration;
 import org.apache.shardingsphere.mcp.support.configuration.MCPConfigurationValidator;
 import org.junit.jupiter.api.Test;
 
@@ -132,11 +133,12 @@ class MCPLaunchConfigurationTest {
         return result;
     }
     
-    private Map<String, Map<String, Object>> createRuntimeDatabases() {
-        return Collections.singletonMap("logic_db", Map.of(
-                "jdbcUrl", "jdbc:mysql://localhost:3306/logic_db",
-                "username", "demo",
-                "password", "",
-                "driverClassName", "com.mysql.cj.jdbc.Driver"));
+    private Map<String, YamlRuntimeDatabaseConfiguration> createRuntimeDatabases() {
+        YamlRuntimeDatabaseConfiguration result = new YamlRuntimeDatabaseConfiguration();
+        result.setJdbcUrl("jdbc:mysql://localhost:3306/logic_db");
+        result.setUsername("demo");
+        result.setPassword("");
+        result.setDriverClassName("com.mysql.cj.jdbc.Driver");
+        return Collections.singletonMap("logic_db", result);
     }
 }
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlMCPLaunchConfigurationSwapperTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlMCPLaunchConfigurationSwapperTest.java
index 665f29d86e8..c4c79889cbc 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlMCPLaunchConfigurationSwapperTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlMCPLaunchConfigurationSwapperTest.java
@@ -85,7 +85,7 @@ class YamlMCPLaunchConfigurationSwapperTest {
                 + "    username: demo\n"
                 + "    driverClassName: ''\n";
         IllegalArgumentException actual = assertThrows(IllegalArgumentException.class, () -> swapper.swapToObject(YamlEngine.unmarshal(yamlContent, YamlMCPLaunchConfiguration.class)));
-        assertThat(actual.getMessage(), is("MCP launch configuration property `runtimeDatabases` contains database `logic_db` property `driverClassName` is required."));
+        assertThat(actual.getMessage(), is("MCP launch configuration property `runtimeDatabases[logic_db].driverClassName` is required."));
     }
     
     @Test
@@ -252,8 +252,8 @@ class YamlMCPLaunchConfigurationSwapperTest {
                 + "    password: ''\n"
                 + "    driverClassName: com.mysql.cj.jdbc.Driver\n"
                 + "    unsupported: true\n";
-        IllegalArgumentException actual = assertThrows(IllegalArgumentException.class, () -> swapper.swapToObject(YamlEngine.unmarshal(yamlContent, YamlMCPLaunchConfiguration.class)));
-        assertThat(actual.getMessage(), is("MCP launch configuration property `runtimeDatabases` contains unsupported property `unsupported` for database `logic_db`."));
+        ConstructorException actual = assertThrows(ConstructorException.class, () -> swapper.swapToObject(YamlEngine.unmarshal(yamlContent, YamlMCPLaunchConfiguration.class)));
+        assertThat(actual.getMessage(), containsString("Unable to find property 'unsupported'"));
     }
     
     @Test
@@ -304,7 +304,7 @@ class YamlMCPLaunchConfigurationSwapperTest {
         databases.put("logic_db", new RuntimeDatabaseConfiguration("jdbc:mysql://localhost:3306/logic_db", "demo", "", "com.mysql.cj.jdbc.Driver"));
         MCPLaunchConfiguration launchConfig = new MCPLaunchConfiguration(MCPTransportType.HTTP, new HttpTransportConfiguration("127.0.0.1", 18088, "/mcp"), databases);
         YamlMCPLaunchConfiguration actual = swapper.swapToYamlConfiguration(launchConfig);
-        assertThat(String.valueOf(actual.getRuntimeDatabases().get("logic_db").get("username")), is("demo"));
+        assertThat(actual.getRuntimeDatabases().get("logic_db").getUsername(), is("demo"));
         assertThat(actual.getTransport().getType(), is(MCPTransportType.HTTP));
         assertThat(actual.getTransport().getHttp().getBindHost(), is("127.0.0.1"));
     }
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapperTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapperTest.java
index 69eb284fc08..aa5455dfa6f 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapperTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/config/yaml/swapper/YamlRuntimeDatabaseConfigurationsSwapperTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.mcp.bootstrap.config.yaml.swapper;
 
+import org.apache.shardingsphere.mcp.bootstrap.config.yaml.config.YamlRuntimeDatabaseConfiguration;
 import org.apache.shardingsphere.mcp.support.database.metadata.jdbc.RuntimeDatabaseConfiguration;
 import org.junit.jupiter.api.Test;
 
@@ -34,21 +35,16 @@ class YamlRuntimeDatabaseConfigurationsSwapperTest {
     
     @Test
     void assertSwapToObject() {
-        Map<String, RuntimeDatabaseConfiguration> actual = swapper.swapToObject(Map.of("logic_db", Map.of(
-                "jdbcUrl", "jdbc:mysql://localhost:3306/logic_db",
-                "username", "demo",
-                "password", "",
-                "driverClassName", "com.mysql.cj.jdbc.Driver")));
+        Map<String, RuntimeDatabaseConfiguration> actual = swapper.swapToObject(Map.of(
+                "logic_db", createYamlRuntimeDatabaseConfiguration("jdbc:mysql://localhost:3306/logic_db", "demo", "", "com.mysql.cj.jdbc.Driver")));
         
         assertThat(actual.get("logic_db").getJdbcUrl(), is("jdbc:mysql://localhost:3306/logic_db"));
     }
     
     @Test
     void assertSwapToObjectWithPasswordMissing() {
-        Map<String, RuntimeDatabaseConfiguration> actual = swapper.swapToObject(Map.of("logic_db", Map.of(
-                "jdbcUrl", "jdbc:mysql://localhost:3306/logic_db",
-                "username", "demo",
-                "driverClassName", "com.mysql.cj.jdbc.Driver")));
+        Map<String, RuntimeDatabaseConfiguration> actual = swapper.swapToObject(Map.of(
+                "logic_db", createYamlRuntimeDatabaseConfiguration("jdbc:mysql://localhost:3306/logic_db", "demo", null, "com.mysql.cj.jdbc.Driver")));
         
         assertThat(actual.get("logic_db").getPassword(), is(""));
     }
@@ -62,7 +58,7 @@ class YamlRuntimeDatabaseConfigurationsSwapperTest {
     
     @Test
     void assertSwapToObjectWithNullRuntimeDatabaseConfiguration() {
-        Map<String, Map<String, Object>> yamlRuntimeConfiguration = new LinkedHashMap<>(1, 1F);
+        Map<String, YamlRuntimeDatabaseConfiguration> yamlRuntimeConfiguration = new LinkedHashMap<>(1, 1F);
         yamlRuntimeConfiguration.put("logic_db", null);
         
         IllegalArgumentException actual = assertThrows(IllegalArgumentException.class, () -> swapper.swapToObject(yamlRuntimeConfiguration));
@@ -70,24 +66,12 @@ class YamlRuntimeDatabaseConfigurationsSwapperTest {
         assertThat(actual.getMessage(), is("MCP runtime database configuration cannot be null."));
     }
     
-    @Test
-    void assertSwapToObjectWithUnsupportedRuntimeDatabaseProperty() {
-        IllegalArgumentException actual = assertThrows(IllegalArgumentException.class, () -> swapper.swapToObject(Map.of("logic_db", Map.of(
-                "jdbcUrl", "jdbc:mysql://localhost:3306/logic_db",
-                "username", "demo",
-                "password", "",
-                "driverClassName", "com.mysql.cj.jdbc.Driver",
-                "unsupported", true))));
-        
-        assertThat(actual.getMessage(), is("Unsupported runtime database property `unsupported`."));
-    }
-    
     @Test
     void assertSwapToYamlConfiguration() {
-        Map<String, Map<String, Object>> actual = swapper.swapToYamlConfiguration(Map.of(
+        Map<String, YamlRuntimeDatabaseConfiguration> actual = swapper.swapToYamlConfiguration(Map.of(
                 "logic_db", new RuntimeDatabaseConfiguration("jdbc:mysql://localhost:3306/logic_db", "demo", "", "com.mysql.cj.jdbc.Driver")));
         
-        assertThat(String.valueOf(actual.get("logic_db").get("driverClassName")), is("com.mysql.cj.jdbc.Driver"));
+        assertThat(actual.get("logic_db").getDriverClassName(), is("com.mysql.cj.jdbc.Driver"));
     }
     
     @Test
@@ -99,4 +83,13 @@ class YamlRuntimeDatabaseConfigurationsSwapperTest {
         
         assertThat(actual.getMessage(), is("Runtime database configuration cannot be null."));
     }
+    
+    private YamlRuntimeDatabaseConfiguration createYamlRuntimeDatabaseConfiguration(final String jdbcUrl, final String username, final String password, final String driverClassName) {
+        YamlRuntimeDatabaseConfiguration result = new YamlRuntimeDatabaseConfiguration();
+        result.setJdbcUrl(jdbcUrl);
+        result.setUsername(username);
+        result.setPassword(password);
+        result.setDriverClassName(driverClassName);
+        return result;
+    }
 }
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactory.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactory.java
index 3512c19a35b..d1d9eedde0b 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactory.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactory.java
@@ -276,10 +276,8 @@ public final class MetadataResourceResponseFactory {
         Map<String, Object> result = new LinkedHashMap<>(4, 1F);
         String uriTemplate = descriptor.getUriTemplate();
         Optional<String> selfUri = new MCPUriTemplate(uriTemplate).expandIfComplete(uriVariables);
-        selfUri.ifPresent(uri -> {
-            result.put(MCPPayloadFieldNames.SELF_RESOURCE,
-                    MCPResourceHintUtils.create(uri, resolveResourceKind(uri), "inspect_self", "Read this metadata resource.", MCPPayloadFieldNames.SELF_RESOURCE));
-        });
+        selfUri.ifPresent(uri -> result.put(MCPPayloadFieldNames.SELF_RESOURCE,
+                MCPResourceHintUtils.create(uri, resolveResourceKind(uri), "inspect_self", "Read this metadata resource.", MCPPayloadFieldNames.SELF_RESOURCE)));
         String parentUri = createParentUri(selfUri.orElse(""));
         if (!parentUri.isEmpty()) {
             result.put(MCPPayloadFieldNames.PARENT_RESOURCE, MCPResourceHintUtils.create(parentUri, resolveResourceKind(parentUri), "inspect_parent",
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 34a97add9fb..fece5edf28c 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
@@ -47,6 +47,7 @@ import org.apache.shardingsphere.mcp.support.workflow.spi.MCPWorkflowApplyArtifa
 import org.apache.shardingsphere.mcp.support.workflow.spi.MCPWorkflowApplySynchronizationHandler;
 
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -103,7 +104,7 @@ public final class WorkflowExecutionService {
         if (executionMode.isEmpty()) {
             throw new MCPExecutionModeRequiredException(WorkflowToolDescriptors.APPLY_TOOL_NAME, EXECUTION_MODES, createPreviewSuggestedArguments(snapshot));
         }
-        String result = executionMode.toLowerCase();
+        String result = executionMode.toLowerCase(Locale.ENGLISH);
         if (!EXECUTION_MODES.contains(result)) {
             throw new MCPInvalidExecutionModeException(WorkflowToolDescriptors.APPLY_TOOL_NAME, EXECUTION_MODES, createPreviewSuggestedArguments(snapshot));
         }
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowProxyQueryService.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowProxyQueryService.java
index b27d2216dcf..d929d63d919 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowProxyQueryService.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowProxyQueryService.java
@@ -39,6 +39,7 @@ import java.sql.Statement;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
@@ -108,7 +109,7 @@ public final class WorkflowProxyQueryService implements MCPFeatureQueryFacade {
         while (resultSet.next()) {
             Map<String, Object> row = new LinkedHashMap<>(resultSetMetaData.getColumnCount(), 1F);
             for (int index = 1; index <= resultSetMetaData.getColumnCount(); index++) {
-                row.put(resultSetMetaData.getColumnLabel(index).toLowerCase(), resultSet.getObject(index));
+                row.put(resultSetMetaData.getColumnLabel(index).toLowerCase(Locale.ENGLISH), resultSet.getObject(index));
             }
             result.add(row);
         }
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 18337b9d077..77e207b4370 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
@@ -1796,13 +1796,6 @@ tools:
       destructiveHint: true
       idempotentHint: false
       openWorldHint: true
-    runtime:
-      sideEffectScope:
-        - physical-data
-        - physical-structure
-        - privilege-metadata
-        - rule-metadata
-        - transaction-state
     meta:
       org.apache.shardingsphere/related-resource-uris:
         - "shardingsphere://databases/{database}/capabilities"
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactoryTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactoryTest.java
index 0051d76fb88..62dd90533ef 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactoryTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/resource/handler/metadata/MetadataResourceResponseFactoryTest.java
@@ -65,14 +65,20 @@ class MetadataResourceResponseFactoryTest {
         assertThat(actual.get("object_scope"), is("logical-database"));
         assertThat(actual.get("items"), is(List.of(Map.of("database", "逻辑 库/2026?"))));
         String expectedSelfUri = "shardingsphere://databases/%E9%80%BB%E8%BE%91%20%E5%BA%93%2F2026%3F";
-        assertThat(((Map<?, ?>) actual.get("self_resource")).get("uri"), is(expectedSelfUri));
-        assertThat(((Map<?, ?>) actual.get("parent_resource")).get("uri"), is("shardingsphere://databases"));
+        Map<?, ?> actualSelfResource = (Map<?, ?>) actual.get("self_resource");
+        assertThat(actualSelfResource.get("uri"), is(expectedSelfUri));
+        assertThat(actualSelfResource.get("resource_kind"), is("logical-database"));
+        Map<?, ?> actualParentResource = (Map<?, ?>) actual.get("parent_resource");
+        assertThat(actualParentResource.get("uri"), is("shardingsphere://databases"));
+        assertThat(actualParentResource.get("resource_kind"), is("logical-database"));
         List<String> nextResourceUris = ((List<?>) actual.get("next_resources")).stream().map(each -> (String) ((Map<?, ?>) each).get("uri")).toList();
         assertThat(nextResourceUris, is(List.of(
                 expectedSelfUri + "/schemas",
                 expectedSelfUri + "/storage-units",
                 expectedSelfUri + "/single-tables",
                 expectedSelfUri + "/single-table/default-storage-unit")));
+        List<String> nextResourceKinds = ((List<?>) actual.get("next_resources")).stream().map(each -> (String) ((Map<?, ?>) each).get("resource_kind")).toList();
+        assertThat(nextResourceKinds, is(List.of("schema", "storage-unit", "single-table", "single-table")));
     }
     
     @Test
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/MetadataSearchResourceUriFactoryTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/MetadataSearchResourceUriFactoryTest.java
new file mode 100644
index 00000000000..e72544d1344
--- /dev/null
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/MetadataSearchResourceUriFactoryTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.mcp.core.tool.handler.metadata;
+
+import org.apache.shardingsphere.mcp.core.tool.handler.metadata.MetadataSearchResourceUriFactory.MetadataResourceUris;
+import org.apache.shardingsphere.mcp.support.database.capability.SupportedMCPMetadataObjectType;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+class MetadataSearchResourceUriFactoryTest {
+    
+    @Test
+    void assertCreateDatabaseResourceKinds() {
+        MetadataResourceUris actual = new MetadataSearchResourceUriFactory().create("logic_db", "", SupportedMCPMetadataObjectType.DATABASE, "", "", "");
+        assertThat(actual.resource().get("resource_kind"), is("database"));
+        assertThat(actual.parentResource().get("resource_kind"), is("database"));
+        assertThat(actual.nextResources().stream().map(each -> each.get("resource_kind")).toList(), is(List.of("database", "schema")));
+    }
+    
+    @Test
+    void assertCreateTableResourceKinds() {
+        MetadataResourceUris actual = new MetadataSearchResourceUriFactory().create("logic_db", "public", SupportedMCPMetadataObjectType.TABLE, "orders", "", "");
+        assertThat(actual.resource().get("resource_kind"), is("table"));
+        assertThat(actual.parentResource().get("resource_kind"), is("table"));
+        assertThat(actual.nextResources().stream().map(each -> each.get("resource_kind")).toList(), is(List.of("column", "index")));
+    }
+    
+    @Test
+    void assertCreateStorageUnitResourceKinds() {
+        MetadataResourceUris actual = new MetadataSearchResourceUriFactory().create("logic_db", "", SupportedMCPMetadataObjectType.STORAGE_UNIT, "", "", "write_ds");
+        assertThat(actual.resource().get("resource_kind"), is("storage-unit"));
+        assertThat(actual.parentResource().get("resource_kind"), is("storage-unit"));
+        assertThat(actual.nextResources().stream().map(each -> each.get("resource_kind")).toList(), is(List.of("storage-unit")));
+    }
+}
diff --git a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/completion/EncryptAlgorithmCompletionHandler.java b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/completion/EncryptAlgorithmCompletionHandler.java
index f3700afe080..9bbb672d220 100644
--- a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/completion/EncryptAlgorithmCompletionHandler.java
+++ b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/completion/EncryptAlgorithmCompletionHandler.java
@@ -55,7 +55,7 @@ public final class EncryptAlgorithmCompletionHandler implements MCPCompletionHan
     
     @Override
     public MCPCompletionHandlerResult complete(final MCPFeatureRequestContext handlerContext, final MCPCompletionRequest request) {
-        return new MCPCompletionHandlerResult(ruleInspectionService.queryEncryptAlgorithms(handlerContext.getQueryFacade()).stream()
+        return new MCPCompletionHandlerResult(ruleInspectionService.queryEncryptAlgorithms(handlerContext.getQueryFacade()).getRows().stream()
                 .map(this::createAlgorithmCandidate).filter(each -> !each.getValue().isEmpty()).toList());
     }
     
diff --git a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandler.java b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandler.java
index 9f0cde1ffa9..cf790eeb479 100644
--- a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandler.java
+++ b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandler.java
@@ -46,7 +46,7 @@ public final class EncryptAlgorithmsHandler implements MCPResourceHandler<MCPFea
     
     @Override
     public MCPSuccessPayload handle(final MCPFeatureRequestContext requestContext, final MCPResourceURIVariables uriVariables) {
-        return new MCPItemsPayload(ruleInspectionService.queryEncryptAlgorithms(requestContext.getQueryFacade()),
+        return new MCPItemsPayload(ruleInspectionService.queryEncryptAlgorithms(requestContext.getQueryFacade()).getRows(),
                 MCPResourceNavigationPayloadBuilder.create(MCPDescriptorCatalogIndex.getRequiredResourceDescriptor(getResourceUriTemplate()), uriVariables));
     }
 }
diff --git a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationService.java b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationService.java
index e902b08aa90..b5734562aa3 100644
--- a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationService.java
+++ b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationService.java
@@ -23,6 +23,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.AlgorithmCandidate;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowLifecycle;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowAlgorithmUtils;
 
 import java.util.LinkedList;
@@ -38,48 +39,48 @@ public final class EncryptAlgorithmRecommendationService {
      * Recommend encrypt algorithms.
      *
      * @param request workflow request
-     * @param encryptAlgorithms encrypt algorithm plugins
+     * @param algorithmResult encrypt algorithm query result
      * @param issues workflow issues
      * @return selected candidates
      */
     public List<AlgorithmCandidate> recommendEncryptAlgorithms(final EncryptWorkflowRequest request,
-                                                               final List<Map<String, Object>> encryptAlgorithms, final List<WorkflowIssue> issues) {
+                                                               final WorkflowQueryResult algorithmResult, final List<WorkflowIssue> issues) {
         List<AlgorithmCandidate> result = new LinkedList<>();
-        String primaryType = resolvePrimaryEncryptAlgorithm(request, encryptAlgorithms, issues);
+        String primaryType = resolvePrimaryEncryptAlgorithm(request, algorithmResult, issues);
         if (!primaryType.isEmpty()) {
             result.add(createEncryptCandidate(EncryptFeatureDefinition.ALGORITHM_ROLE_PRIMARY, primaryType, request));
         }
         if (Boolean.TRUE.equals(request.getOptions().getRequiresEqualityFilter())) {
-            addAssistedQueryCandidate(result, request, encryptAlgorithms, issues);
+            addAssistedQueryCandidate(result, request, algorithmResult, issues);
         }
         if (Boolean.TRUE.equals(request.getOptions().getRequiresLikeQuery())) {
-            addLikeQueryCandidate(result, request, encryptAlgorithms, issues);
+            addLikeQueryCandidate(result, request, algorithmResult, issues);
         }
         return result;
     }
     
-    private String resolvePrimaryEncryptAlgorithm(final EncryptWorkflowRequest request, final List<Map<String, Object>> encryptAlgorithms,
+    private String resolvePrimaryEncryptAlgorithm(final EncryptWorkflowRequest request, final WorkflowQueryResult algorithmResult,
                                                   final List<WorkflowIssue> issues) {
         String actualAlgorithmType = WorkflowAlgorithmUtils.normalizeAlgorithmType(request.getAlgorithmType());
         if (!actualAlgorithmType.isEmpty()) {
-            return resolveSpecifiedPrimaryEncryptAlgorithm(request, encryptAlgorithms, issues, actualAlgorithmType);
+            return resolveSpecifiedPrimaryEncryptAlgorithm(request, algorithmResult, issues, actualAlgorithmType);
         }
         if (Boolean.TRUE.equals(request.getOptions().getRequiresLikeQuery())) {
-            for (Map<String, Object> each : encryptAlgorithms) {
+            for (Map<String, Object> each : algorithmResult.getRows()) {
                 if (Boolean.TRUE.equals(each.get(EncryptFeatureDefinition.ALGORITHM_CAPABILITY_LIKE))) {
                     return WorkflowAlgorithmUtils.getAlgorithmType(each);
                 }
             }
         }
-        if (WorkflowAlgorithmUtils.containsAlgorithm(encryptAlgorithms, "AES")) {
+        if (WorkflowAlgorithmUtils.containsAlgorithm(algorithmResult.getRows(), "AES")) {
             return "AES";
         }
-        return encryptAlgorithms.isEmpty() ? "" : WorkflowAlgorithmUtils.getAlgorithmType(encryptAlgorithms.getFirst());
+        return algorithmResult.getRows().isEmpty() ? "" : WorkflowAlgorithmUtils.getAlgorithmType(algorithmResult.getRows().getFirst());
     }
     
-    private String resolveSpecifiedPrimaryEncryptAlgorithm(final EncryptWorkflowRequest request, final List<Map<String, Object>> encryptAlgorithms,
+    private String resolveSpecifiedPrimaryEncryptAlgorithm(final EncryptWorkflowRequest request, final WorkflowQueryResult algorithmResult,
                                                            final List<WorkflowIssue> issues, final String algorithmType) {
-        if (!WorkflowAlgorithmUtils.containsAlgorithm(encryptAlgorithms, algorithmType)) {
+        if (algorithmResult.isAvailabilityConfirmed() && !WorkflowAlgorithmUtils.containsAlgorithm(algorithmResult.getRows(), algorithmType)) {
             issues.add(new WorkflowIssue(WorkflowIssueCode.ALGORITHM_NOT_FOUND, "error", WorkflowLifecycle.STEP_SELECTING_ALGORITHM,
                     String.format("Encrypt algorithm `%s` is not visible from the current Proxy.", algorithmType), "Choose an available encrypt algorithm.", false, Map.of()));
             return "";
@@ -94,8 +95,8 @@ public final class EncryptAlgorithmRecommendationService {
     }
     
     private void addAssistedQueryCandidate(final List<AlgorithmCandidate> candidates, final EncryptWorkflowRequest request,
-                                           final List<Map<String, Object>> encryptAlgorithms, final List<WorkflowIssue> issues) {
-        String assistedQueryType = resolveAssistedQueryAlgorithm(request, encryptAlgorithms, issues);
+                                           final WorkflowQueryResult algorithmResult, final List<WorkflowIssue> issues) {
+        String assistedQueryType = resolveAssistedQueryAlgorithm(request, algorithmResult, issues);
         if (assistedQueryType.isEmpty()) {
             addCapabilityConflictIssue(issues, request.getOptions().getAssistedQueryAlgorithmType(),
                     "No assisted-query algorithm is available for the current requirement.", "Install or specify a supported assisted-query algorithm.");
@@ -106,8 +107,8 @@ public final class EncryptAlgorithmRecommendationService {
     }
     
     private void addLikeQueryCandidate(final List<AlgorithmCandidate> candidates, final EncryptWorkflowRequest request,
-                                       final List<Map<String, Object>> encryptAlgorithms, final List<WorkflowIssue> issues) {
-        String likeQueryType = resolveLikeQueryAlgorithm(request, encryptAlgorithms, issues);
+                                       final WorkflowQueryResult algorithmResult, final List<WorkflowIssue> issues) {
+        String likeQueryType = resolveLikeQueryAlgorithm(request, algorithmResult, issues);
         if (likeQueryType.isEmpty()) {
             addCapabilityConflictIssue(issues, request.getOptions().getLikeQueryAlgorithmType(),
                     "No like-query algorithm is available for the current requirement.", "Install or specify a supported like-query algorithm.");
@@ -124,17 +125,17 @@ public final class EncryptAlgorithmRecommendationService {
         issues.add(new WorkflowIssue(WorkflowIssueCode.ALGORITHM_CAPABILITY_CONFLICT, "error", WorkflowLifecycle.STEP_SELECTING_ALGORITHM, message, userAction, false, Map.of()));
     }
     
-    private String resolveAssistedQueryAlgorithm(final EncryptWorkflowRequest request, final List<Map<String, Object>> encryptAlgorithms,
+    private String resolveAssistedQueryAlgorithm(final EncryptWorkflowRequest request, final WorkflowQueryResult algorithmResult,
                                                  final List<WorkflowIssue> issues) {
         String actualAlgorithmType = WorkflowAlgorithmUtils.normalizeAlgorithmType(request.getOptions().getAssistedQueryAlgorithmType());
         if (!actualAlgorithmType.isEmpty()) {
-            return resolveSpecifiedAssistedQueryAlgorithm(encryptAlgorithms, issues, actualAlgorithmType);
+            return resolveSpecifiedAssistedQueryAlgorithm(algorithmResult, issues, actualAlgorithmType);
         }
-        return WorkflowAlgorithmUtils.containsAlgorithm(encryptAlgorithms, "MD5") ? "MD5" : "";
+        return WorkflowAlgorithmUtils.containsAlgorithm(algorithmResult.getRows(), "MD5") ? "MD5" : "";
     }
     
-    private String resolveSpecifiedAssistedQueryAlgorithm(final List<Map<String, Object>> encryptAlgorithms, final List<WorkflowIssue> issues, final String algorithmType) {
-        if (!WorkflowAlgorithmUtils.containsAlgorithm(encryptAlgorithms, algorithmType)) {
+    private String resolveSpecifiedAssistedQueryAlgorithm(final WorkflowQueryResult algorithmResult, final List<WorkflowIssue> issues, final String algorithmType) {
+        if (algorithmResult.isAvailabilityConfirmed() && !WorkflowAlgorithmUtils.containsAlgorithm(algorithmResult.getRows(), algorithmType)) {
             issues.add(new WorkflowIssue(WorkflowIssueCode.ALGORITHM_NOT_FOUND, "error", WorkflowLifecycle.STEP_SELECTING_ALGORITHM,
                     String.format("Assisted-query algorithm `%s` is not visible from the current Proxy.", algorithmType),
                     "Choose an available assisted-query algorithm.", false, Map.of()));
@@ -143,13 +144,13 @@ public final class EncryptAlgorithmRecommendationService {
         return algorithmType;
     }
     
-    private String resolveLikeQueryAlgorithm(final EncryptWorkflowRequest request, final List<Map<String, Object>> encryptAlgorithms,
+    private String resolveLikeQueryAlgorithm(final EncryptWorkflowRequest request, final WorkflowQueryResult algorithmResult,
                                              final List<WorkflowIssue> issues) {
         String actualAlgorithmType = WorkflowAlgorithmUtils.normalizeAlgorithmType(request.getOptions().getLikeQueryAlgorithmType());
         if (!actualAlgorithmType.isEmpty()) {
-            return resolveSpecifiedLikeQueryAlgorithm(encryptAlgorithms, issues, actualAlgorithmType);
+            return resolveSpecifiedLikeQueryAlgorithm(algorithmResult, issues, actualAlgorithmType);
         }
-        for (Map<String, Object> each : encryptAlgorithms) {
+        for (Map<String, Object> each : algorithmResult.getRows()) {
             if (Boolean.TRUE.equals(each.get(EncryptFeatureDefinition.ALGORITHM_CAPABILITY_LIKE))) {
                 return WorkflowAlgorithmUtils.getAlgorithmType(each);
             }
@@ -157,8 +158,8 @@ public final class EncryptAlgorithmRecommendationService {
         return "";
     }
     
-    private String resolveSpecifiedLikeQueryAlgorithm(final List<Map<String, Object>> encryptAlgorithms, final List<WorkflowIssue> issues, final String algorithmType) {
-        if (!WorkflowAlgorithmUtils.containsAlgorithm(encryptAlgorithms, algorithmType)) {
+    private String resolveSpecifiedLikeQueryAlgorithm(final WorkflowQueryResult algorithmResult, final List<WorkflowIssue> issues, final String algorithmType) {
+        if (algorithmResult.isAvailabilityConfirmed() && !WorkflowAlgorithmUtils.containsAlgorithm(algorithmResult.getRows(), algorithmType)) {
             issues.add(new WorkflowIssue(WorkflowIssueCode.ALGORITHM_NOT_FOUND, "error", WorkflowLifecycle.STEP_SELECTING_ALGORITHM,
                     String.format("LIKE-query algorithm `%s` is not visible from the current Proxy.", algorithmType),
                     "Choose an available LIKE-query algorithm.", false, Map.of()));
diff --git a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionService.java b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionService.java
index 0278cc8dcaa..94efd197885 100644
--- a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionService.java
+++ b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionService.java
@@ -21,6 +21,7 @@ import org.apache.shardingsphere.mcp.api.exception.MCPQueryFailedException;
 import org.apache.shardingsphere.mcp.feature.encrypt.EncryptFeatureDefinition;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.apache.shardingsphere.mcp.support.workflow.model.AlgorithmPropertyRequirement;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowAlgorithmUtils;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowDistSQLQueryUtils;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowSQLUtils;
@@ -66,9 +67,10 @@ public final class EncryptRuleInspectionService {
      * @param queryFacade query facade
      * @return encrypt algorithms
      */
-    public List<Map<String, Object>> queryEncryptAlgorithms(final MCPFeatureQueryFacade queryFacade) {
+    public WorkflowQueryResult queryEncryptAlgorithms(final MCPFeatureQueryFacade queryFacade) {
+        WorkflowQueryResult algorithmResult = queryAlgorithmRows(queryFacade);
         List<Map<String, Object>> result = new LinkedList<>();
-        for (Map<String, Object> each : queryAlgorithmRows(queryFacade)) {
+        for (Map<String, Object> each : algorithmResult.getRows()) {
             String type = WorkflowAlgorithmUtils.getAlgorithmType(each);
             Map<String, Boolean> capability = EncryptAlgorithmCatalog.findCapability(type);
             List<AlgorithmPropertyRequirement> propertyTemplates = EncryptAlgorithmCatalog.findRequirements(EncryptFeatureDefinition.ALGORITHM_ROLE_PRIMARY, type);
@@ -83,15 +85,15 @@ public final class EncryptRuleInspectionService {
             row.put("secret_properties", propertyTemplates.stream().filter(AlgorithmPropertyRequirement::isSecret).map(AlgorithmPropertyRequirement::getPropertyKey).toList());
             result.add(row);
         }
-        return result;
+        return new WorkflowQueryResult(result, algorithmResult.isAvailabilityConfirmed());
     }
     
-    private List<Map<String, Object>> queryAlgorithmRows(final MCPFeatureQueryFacade queryFacade) {
+    private WorkflowQueryResult queryAlgorithmRows(final MCPFeatureQueryFacade queryFacade) {
         try {
-            return queryFacade.queryWithAnyDatabase("SHOW ENCRYPT ALGORITHM PLUGINS");
+            return WorkflowQueryResult.confirmed(queryFacade.queryWithAnyDatabase("SHOW ENCRYPT ALGORITHM PLUGINS"));
         } catch (final MCPQueryFailedException ex) {
             if (WorkflowDistSQLQueryUtils.isUnsupportedDistSQLQueryFailure(ex)) {
-                return EncryptAlgorithmCatalog.getSupportedAlgorithmTypes().stream().map(each -> Map.<String, Object>of("type", each)).toList();
+                return WorkflowQueryResult.fallback(EncryptAlgorithmCatalog.getSupportedAlgorithmTypes().stream().map(each -> Map.<String, Object>of("type", each)).toList());
             }
             throw ex;
         }
diff --git a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningService.java b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningService.java
index bbf14107d42..7c7bdcaaade 100644
--- a/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningService.java
+++ b/mcp/features/encrypt/src/main/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningService.java
@@ -32,6 +32,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowFieldNames;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowLifecycle;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowPlanningSupport;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowRuleValueUtils;
 
@@ -200,7 +201,7 @@ public final class EncryptWorkflowPlanningService {
     }
     
     private void planAlgorithms(final MCPFeatureQueryFacade queryFacade, final EncryptWorkflowRequest request, final WorkflowContextSnapshot snapshot) {
-        List<Map<String, Object>> encryptAlgorithms = ruleInspectionService.queryEncryptAlgorithms(queryFacade);
+        WorkflowQueryResult encryptAlgorithms = ruleInspectionService.queryEncryptAlgorithms(queryFacade);
         List<AlgorithmCandidate> algorithmCandidates = algorithmRecommendationService.recommendEncryptAlgorithms(request, encryptAlgorithms, snapshot.getIssues());
         snapshot.getAlgorithmCandidates().addAll(algorithmCandidates);
         applyRecommendedAlgorithms(request, algorithmCandidates);
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandlerTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandlerTest.java
index 4657b1b5f35..ed4a9b9145d 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandlerTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptAlgorithmsHandlerTest.java
@@ -22,6 +22,7 @@ import org.apache.shardingsphere.mcp.api.capability.resource.MCPResourceURIVaria
 import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptRuleInspectionService;
 import org.apache.shardingsphere.mcp.support.MCPFeatureRequestContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.junit.jupiter.api.Test;
 import org.mockito.MockedConstruction;
 
@@ -45,7 +46,7 @@ class EncryptAlgorithmsHandlerTest {
         when(requestContext.getQueryFacade()).thenReturn(queryFacade);
         try (
                 MockedConstruction<EncryptRuleInspectionService> mockedConstruction = mockConstruction(EncryptRuleInspectionService.class,
-                        (mock, context) -> when(mock.queryEncryptAlgorithms(queryFacade)).thenReturn(List.of(Map.of("type", "AES"))))) {
+                        (mock, context) -> when(mock.queryEncryptAlgorithms(queryFacade)).thenReturn(WorkflowQueryResult.confirmed(List.of(Map.of("type", "AES")))))) {
             MCPSuccessPayload actual = new EncryptAlgorithmsHandler().handle(requestContext, new MCPResourceURIVariables(Map.of()));
             verify(mockedConstruction.constructed().getFirst()).queryEncryptAlgorithms(queryFacade);
             assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationServiceTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationServiceTest.java
index 3003a52c801..a5d27126caf 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationServiceTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptAlgorithmRecommendationServiceTest.java
@@ -21,6 +21,7 @@ import org.apache.shardingsphere.mcp.feature.encrypt.tool.model.EncryptWorkflowR
 import org.apache.shardingsphere.mcp.support.workflow.model.AlgorithmCandidate;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.junit.jupiter.api.Test;
 
 import java.util.LinkedHashMap;
@@ -43,7 +44,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         request.getOptions().setRequiresDecrypt(true);
         request.setAlgorithmType("AES");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("AES", true, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("AES", true, true, false)), issues);
         assertThat(actual.size(), is(1));
         assertThat(actual.getFirst().getAlgorithmRole(), is("primary"));
         assertThat(actual.getFirst().getAlgorithmType(), is("AES"));
@@ -56,7 +57,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         request.getOptions().setRequiresDecrypt(true);
         request.setAlgorithmType("MD5");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("MD5", false, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("MD5", false, true, false)), issues);
         assertTrue(actual.isEmpty());
         assertThat(issues.getFirst().getCode(), is(WorkflowIssueCode.ALGORITHM_CAPABILITY_CONFLICT));
     }
@@ -66,7 +67,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         EncryptWorkflowRequest request = new EncryptWorkflowRequest();
         request.setAlgorithmType("SM4");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("AES", true, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("AES", true, true, false)), issues);
         assertTrue(actual.isEmpty());
         assertThat(issues.getFirst().getCode(), is(WorkflowIssueCode.ALGORITHM_NOT_FOUND));
     }
@@ -74,7 +75,7 @@ class EncryptAlgorithmRecommendationServiceTest {
     @Test
     void assertRecommendEncryptAlgorithmsWithoutAvailableAlgorithm() {
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(new EncryptWorkflowRequest(), List.of(), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(new EncryptWorkflowRequest(), WorkflowQueryResult.confirmed(List.of()), issues);
         assertTrue(actual.isEmpty());
         assertTrue(issues.isEmpty());
     }
@@ -83,7 +84,7 @@ class EncryptAlgorithmRecommendationServiceTest {
     void assertRecommendEncryptAlgorithmsFallsBackToFirstAvailableAlgorithm() {
         List<WorkflowIssue> issues = new LinkedList<>();
         List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(
-                new EncryptWorkflowRequest(), List.of(createAlgorithmRow("FPE", null, null, null)), issues);
+                new EncryptWorkflowRequest(), confirmed(createAlgorithmRow("FPE", null, null, null)), issues);
         assertThat(actual.getFirst().getAlgorithmType(), is("FPE"));
         assertTrue(issues.isEmpty());
     }
@@ -93,7 +94,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         EncryptWorkflowRequest request = new EncryptWorkflowRequest();
         request.getOptions().setRequiresEqualityFilter(true);
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("AES", true, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("AES", true, true, false)), issues);
         assertThat(actual.size(), is(1));
         assertThat(actual.getFirst().getAlgorithmType(), is("AES"));
         assertThat(issues.getFirst().getCode(), is(WorkflowIssueCode.ALGORITHM_CAPABILITY_CONFLICT));
@@ -104,7 +105,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         EncryptWorkflowRequest request = new EncryptWorkflowRequest();
         request.getOptions().setRequiresEqualityFilter(true);
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(
                 createAlgorithmRow("AES", true, true, false), createAlgorithmRow("MD5", false, true, false)), issues);
         assertThat(actual.size(), is(2));
         assertThat(actual.get(1).getAlgorithmRole(), is("assisted_query"));
@@ -118,7 +119,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         request.getOptions().setRequiresEqualityFilter(true);
         request.getOptions().setAssistedQueryAlgorithmType("CUSTOM_HASH");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(
                 createAlgorithmRow("AES", true, true, false), createAlgorithmRow("CUSTOM_HASH", null, true, false)), issues);
         assertThat(actual.size(), is(2));
         assertThat(actual.get(1).getAlgorithmType(), is("CUSTOM_HASH"));
@@ -131,7 +132,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         request.getOptions().setRequiresEqualityFilter(true);
         request.getOptions().setAssistedQueryAlgorithmType("MD5");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("AES", true, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("AES", true, true, false)), issues);
         assertThat(actual.size(), is(1));
         assertThat(issues.size(), is(1));
         assertThat(issues.getFirst().getCode(), is(WorkflowIssueCode.ALGORITHM_NOT_FOUND));
@@ -142,7 +143,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         EncryptWorkflowRequest request = new EncryptWorkflowRequest();
         request.setAlgorithmType("FPE");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("FPE", null, null, null)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("FPE", null, null, null)), issues);
         assertThat(actual.size(), is(1));
         assertFalse(actual.getFirst().getRiskNotes().isEmpty());
         assertTrue(issues.isEmpty());
@@ -153,7 +154,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         EncryptWorkflowRequest request = new EncryptWorkflowRequest();
         request.getOptions().setRequiresLikeQuery(true);
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(
                 createAlgorithmRow("AES", true, true, false),
                 createAlgorithmRow("FPE", null, null, true)), issues);
         assertThat(actual.size(), is(2));
@@ -169,7 +170,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         request.getOptions().setRequiresLikeQuery(true);
         request.getOptions().setLikeQueryAlgorithmType("AES");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("AES", true, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("AES", true, true, false)), issues);
         assertThat(actual.size(), is(1));
         assertThat(issues.getFirst().getCode(), is(WorkflowIssueCode.ALGORITHM_CAPABILITY_CONFLICT));
     }
@@ -179,7 +180,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         EncryptWorkflowRequest request = new EncryptWorkflowRequest();
         request.getOptions().setRequiresLikeQuery(true);
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("AES", true, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("AES", true, true, false)), issues);
         assertThat(actual.size(), is(1));
         assertThat(issues.getFirst().getCode(), is(WorkflowIssueCode.ALGORITHM_CAPABILITY_CONFLICT));
     }
@@ -190,7 +191,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         request.getOptions().setRequiresLikeQuery(true);
         request.getOptions().setLikeQueryAlgorithmType("FPE");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(createAlgorithmRow("AES", true, true, false)), issues);
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(createAlgorithmRow("AES", true, true, false)), issues);
         assertThat(actual.size(), is(1));
         assertThat(issues.size(), is(1));
         assertThat(issues.getFirst().getCode(), is(WorkflowIssueCode.ALGORITHM_NOT_FOUND));
@@ -202,7 +203,7 @@ class EncryptAlgorithmRecommendationServiceTest {
         request.getOptions().setRequiresLikeQuery(true);
         request.getOptions().setLikeQueryAlgorithmType("FPE");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, List.of(
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, confirmed(
                 createAlgorithmRow("AES", true, true, false), createAlgorithmRow("FPE", null, null, true)), issues);
         assertThat(actual.size(), is(2));
         assertThat(actual.get(1).getAlgorithmType(), is("FPE"));
@@ -210,6 +211,47 @@ class EncryptAlgorithmRecommendationServiceTest {
         assertTrue(issues.isEmpty());
     }
     
+    @Test
+    void assertRecommendEncryptAlgorithmsWithUnconfirmedAvailability() {
+        EncryptWorkflowRequest request = new EncryptWorkflowRequest();
+        request.setAlgorithmType("CUSTOM");
+        List<WorkflowIssue> issues = new LinkedList<>();
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(request, WorkflowQueryResult.fallback(List.of()), issues);
+        assertThat(actual.getFirst().getAlgorithmType(), is("CUSTOM"));
+        assertTrue(issues.isEmpty());
+    }
+    
+    @Test
+    void assertRecommendAssistedQueryAlgorithmWithUnconfirmedAvailability() {
+        EncryptWorkflowRequest request = new EncryptWorkflowRequest();
+        request.setAlgorithmType("AES");
+        request.getOptions().setRequiresEqualityFilter(true);
+        request.getOptions().setAssistedQueryAlgorithmType("CUSTOM_HASH");
+        List<WorkflowIssue> issues = new LinkedList<>();
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(
+                request, WorkflowQueryResult.fallback(List.of(createAlgorithmRow("AES", true, true, false))), issues);
+        assertThat(actual.get(1).getAlgorithmType(), is("CUSTOM_HASH"));
+        assertTrue(issues.isEmpty());
+    }
+    
+    @Test
+    void assertRecommendLikeQueryAlgorithmWithUnconfirmedAvailability() {
+        EncryptWorkflowRequest request = new EncryptWorkflowRequest();
+        request.setAlgorithmType("AES");
+        request.getOptions().setRequiresLikeQuery(true);
+        request.getOptions().setLikeQueryAlgorithmType("CUSTOM_LIKE");
+        List<WorkflowIssue> issues = new LinkedList<>();
+        List<AlgorithmCandidate> actual = service.recommendEncryptAlgorithms(
+                request, WorkflowQueryResult.fallback(List.of(createAlgorithmRow("AES", true, true, false))), issues);
+        assertThat(actual.get(1).getAlgorithmType(), is("CUSTOM_LIKE"));
+        assertTrue(issues.isEmpty());
+    }
+    
+    @SafeVarargs
+    private WorkflowQueryResult confirmed(final Map<String, Object>... rows) {
+        return WorkflowQueryResult.confirmed(List.of(rows));
+    }
+    
     private Map<String, Object> createAlgorithmRow(final String type, final Boolean decrypt, final Boolean equivalentFilter, final Boolean like) {
         Map<String, Object> result = new LinkedHashMap<>(4, 1F);
         result.put("type", type);
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionServiceTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionServiceTest.java
index 63c66a47b51..2554f2dd1f8 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionServiceTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptRuleInspectionServiceTest.java
@@ -20,6 +20,7 @@ package org.apache.shardingsphere.mcp.feature.encrypt.tool.service;
 import org.apache.shardingsphere.mcp.api.exception.MCPInvalidRequestException;
 import org.apache.shardingsphere.mcp.api.exception.MCPQueryFailedException;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.junit.jupiter.api.Test;
 
 import java.sql.SQLException;
@@ -102,18 +103,19 @@ class EncryptRuleInspectionServiceTest {
     void assertQueryEncryptAlgorithms() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         when(queryFacade.queryWithAnyDatabase("SHOW ENCRYPT ALGORITHM PLUGINS")).thenReturn(List.of(Map.of("type", "AES"), Map.of("type", "CUSTOM")));
-        List<Map<String, Object>> actual = service.queryEncryptAlgorithms(queryFacade);
-        assertTrue((Boolean) actual.getFirst().get("supports_decrypt"));
-        assertTrue((Boolean) actual.getFirst().get("capability_confirmed"));
-        assertThat(actual.getFirst().get("required_properties"), is(List.of("aes-key-value")));
-        assertThat(actual.getFirst().get("optional_properties"), is(List.of("digest-algorithm-name")));
-        assertThat(actual.getFirst().get("secret_properties"), is(List.of("aes-key-value")));
-        List<?> propertyTemplates = (List<?>) actual.getFirst().get("property_templates");
+        WorkflowQueryResult actual = service.queryEncryptAlgorithms(queryFacade);
+        assertTrue((Boolean) actual.getRows().getFirst().get("supports_decrypt"));
+        assertTrue((Boolean) actual.getRows().getFirst().get("capability_confirmed"));
+        assertThat(actual.getRows().getFirst().get("required_properties"), is(List.of("aes-key-value")));
+        assertThat(actual.getRows().getFirst().get("optional_properties"), is(List.of("digest-algorithm-name")));
+        assertThat(actual.getRows().getFirst().get("secret_properties"), is(List.of("aes-key-value")));
+        List<?> propertyTemplates = (List<?>) actual.getRows().getFirst().get("property_templates");
         assertThat(((Map<?, ?>) propertyTemplates.getFirst()).get("property_key"), is("aes-key-value"));
-        assertThat(actual.get(1).get("type"), is("CUSTOM"));
-        assertNull(actual.get(1).get("supports_like"));
-        assertFalse((Boolean) actual.get(1).get("capability_confirmed"));
-        assertThat(actual.get(1).get("property_templates"), is(List.of()));
+        assertThat(actual.getRows().get(1).get("type"), is("CUSTOM"));
+        assertNull(actual.getRows().get(1).get("supports_like"));
+        assertFalse((Boolean) actual.getRows().get(1).get("capability_confirmed"));
+        assertThat(actual.getRows().get(1).get("property_templates"), is(List.of()));
+        assertTrue(actual.isAvailabilityConfirmed());
     }
     
     @Test
@@ -121,9 +123,10 @@ class EncryptRuleInspectionServiceTest {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         when(queryFacade.queryWithAnyDatabase("SHOW ENCRYPT ALGORITHM PLUGINS"))
                 .thenThrow(new MCPQueryFailedException("syntax error near 'ENCRYPT ALGORITHM PLUGINS'", new SQLSyntaxErrorException("syntax error")));
-        List<Map<String, Object>> actual = service.queryEncryptAlgorithms(queryFacade);
-        assertThat(actual.getFirst().get("type"), is("AES"));
-        assertThat(actual.getFirst().get("required_properties"), is(List.of("aes-key-value")));
+        WorkflowQueryResult actual = service.queryEncryptAlgorithms(queryFacade);
+        assertThat(actual.getRows().getFirst().get("type"), is("AES"));
+        assertThat(actual.getRows().getFirst().get("required_properties"), is(List.of("aes-key-value")));
+        assertFalse(actual.isAvailabilityConfirmed());
     }
     
     @Test
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningServiceTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningServiceTest.java
index b0c0cf30cb2..3205f76020e 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningServiceTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowPlanningServiceTest.java
@@ -41,6 +41,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnaps
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowFieldNames;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowPlanPayloadBuilder;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -155,7 +156,7 @@ class EncryptWorkflowPlanningServiceTest {
                                                 final String expectedOperationType, final String expectedFieldSemantics, final String expectedStatus) {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(ruleExists ? List.of(Map.of("logic_column", "phone")) : List.of());
-        when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(List.of(Map.of("type", "AES", "supports_like", false)));
+        when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(WorkflowQueryResult.confirmed(List.of(Map.of("type", "AES", "supports_like", false))));
         EncryptWorkflowRequest request = createNaturalLanguageRequest(naturalLanguageIntent);
         request.getOptions().setCipherColumnName("phone_cipher");
         request.getPrimaryAlgorithmProperties().put("aes-key-value", "123456");
@@ -173,7 +174,7 @@ class EncryptWorkflowPlanningServiceTest {
     void assertPlanStopsOnBlockingAlgorithmIssue() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of());
-        when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(List.of());
+        when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(WorkflowQueryResult.confirmed(List.of()));
         EncryptAlgorithmRecommendationService algorithmRecommendationService = mock(EncryptAlgorithmRecommendationService.class);
         when(algorithmRecommendationService.recommendEncryptAlgorithms(any(), any(), any())).thenAnswer(invocation -> {
             List<WorkflowIssue> issues = invocation.getArgument(2);
@@ -213,9 +214,9 @@ class EncryptWorkflowPlanningServiceTest {
     void assertPlanDoesNotApplyLikeQueryCandidateWithoutExplicitInput() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of());
-        when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(List.of(
+        when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(WorkflowQueryResult.confirmed(List.of(
                 Map.of("type", "AES", "supports_like", false),
-                Map.of("type", "FPE", "supports_like", true)));
+                Map.of("type", "FPE", "supports_like", true))));
         EncryptAlgorithmPropertyTemplateService propertyTemplateService = mock(EncryptAlgorithmPropertyTemplateService.class);
         when(propertyTemplateService.findRequirements(any(), any(), any())).thenReturn(List.of());
         EncryptWorkflowRequest request = createRequest("create");
diff --git a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/completion/MaskAlgorithmCompletionHandler.java b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/completion/MaskAlgorithmCompletionHandler.java
index 757bbd9a242..8bb4d5ecfa2 100644
--- a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/completion/MaskAlgorithmCompletionHandler.java
+++ b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/completion/MaskAlgorithmCompletionHandler.java
@@ -52,7 +52,7 @@ public final class MaskAlgorithmCompletionHandler implements MCPCompletionHandle
     
     @Override
     public MCPCompletionHandlerResult complete(final MCPFeatureRequestContext handlerContext, final MCPCompletionRequest request) {
-        return new MCPCompletionHandlerResult(ruleInspectionService.queryMaskAlgorithms(handlerContext.getQueryFacade()).stream()
+        return new MCPCompletionHandlerResult(ruleInspectionService.queryMaskAlgorithms(handlerContext.getQueryFacade()).getRows().stream()
                 .map(this::createAlgorithmCandidate).filter(each -> !each.getValue().isEmpty()).toList());
     }
     
diff --git a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandler.java b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandler.java
index 94099e45fb7..d0197c4c37a 100644
--- a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandler.java
+++ b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandler.java
@@ -46,7 +46,7 @@ public final class MaskAlgorithmsHandler implements MCPResourceHandler<MCPFeatur
     
     @Override
     public MCPSuccessPayload handle(final MCPFeatureRequestContext requestContext, final MCPResourceURIVariables uriVariables) {
-        return new MCPItemsPayload(ruleInspectionService.queryMaskAlgorithms(requestContext.getQueryFacade()),
+        return new MCPItemsPayload(ruleInspectionService.queryMaskAlgorithms(requestContext.getQueryFacade()).getRows(),
                 MCPResourceNavigationPayloadBuilder.create(MCPDescriptorCatalogIndex.getRequiredResourceDescriptor(getResourceUriTemplate()), uriVariables));
     }
 }
diff --git a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationService.java b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationService.java
index f2a83f723c5..49e9be072ba 100644
--- a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationService.java
+++ b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationService.java
@@ -22,6 +22,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.ClarifiedIntent;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowLifecycle;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowRequest;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowAlgorithmUtils;
 
@@ -39,15 +40,15 @@ public final class MaskAlgorithmRecommendationService {
      *
      * @param intent clarified intent
      * @param request workflow request
-     * @param maskAlgorithms mask algorithm plugins
+     * @param algorithmResult mask algorithm query result
      * @param issues workflow issues
      * @return selected candidates
      */
     public List<AlgorithmCandidate> recommendMaskAlgorithms(final ClarifiedIntent intent, final WorkflowRequest request,
-                                                            final List<Map<String, Object>> maskAlgorithms, final List<WorkflowIssue> issues) {
+                                                            final WorkflowQueryResult algorithmResult, final List<WorkflowIssue> issues) {
         String actualAlgorithmType = WorkflowAlgorithmUtils.normalizeAlgorithmType(request.getAlgorithmType());
         if (!actualAlgorithmType.isEmpty()) {
-            if (WorkflowAlgorithmUtils.containsAlgorithm(maskAlgorithms, actualAlgorithmType)) {
+            if (!algorithmResult.isAvailabilityConfirmed() || WorkflowAlgorithmUtils.containsAlgorithm(algorithmResult.getRows(), actualAlgorithmType)) {
                 return List.of(AlgorithmCandidate.builder().algorithmRole("primary").algorithmType(actualAlgorithmType).recommendationScore(100)
                         .recommendationReason("User specified algorithm.").riskNotes("").build());
             }
@@ -55,7 +56,7 @@ public final class MaskAlgorithmRecommendationService {
                     String.format("Mask algorithm `%s` is not visible from the current Proxy.", actualAlgorithmType), "Choose an available mask algorithm.", false, Map.of()));
             return List.of();
         }
-        String recommendedType = resolveRecommendedAlgorithm(intent, request, maskAlgorithms);
+        String recommendedType = resolveRecommendedAlgorithm(intent, request, algorithmResult.getRows());
         if (recommendedType.isEmpty()) {
             issues.add(new WorkflowIssue(WorkflowIssueCode.ALGORITHM_NOT_FOUND, "error", WorkflowLifecycle.STEP_SELECTING_ALGORITHM,
                     "No mask algorithm is available from the current Proxy.", "Install or register at least one visible mask algorithm.", false, Map.of()));
diff --git a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionService.java b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionService.java
index 209602485e8..79cbc641b60 100644
--- a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionService.java
+++ b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionService.java
@@ -20,6 +20,7 @@ package org.apache.shardingsphere.mcp.feature.mask.tool.service;
 import org.apache.shardingsphere.mcp.api.exception.MCPQueryFailedException;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.apache.shardingsphere.mcp.support.workflow.model.AlgorithmPropertyRequirement;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowAlgorithmUtils;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowDistSQLQueryUtils;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowSQLUtils;
@@ -66,16 +67,17 @@ public final class MaskRuleInspectionService {
      * @param queryFacade query facade
      * @return mask algorithms
      */
-    public List<Map<String, Object>> queryMaskAlgorithms(final MCPFeatureQueryFacade queryFacade) {
-        return decorateMaskAlgorithms(queryAlgorithmRows(queryFacade));
+    public WorkflowQueryResult queryMaskAlgorithms(final MCPFeatureQueryFacade queryFacade) {
+        WorkflowQueryResult result = queryAlgorithmRows(queryFacade);
+        return new WorkflowQueryResult(decorateMaskAlgorithms(result.getRows()), result.isAvailabilityConfirmed());
     }
     
-    private List<Map<String, Object>> queryAlgorithmRows(final MCPFeatureQueryFacade queryFacade) {
+    private WorkflowQueryResult queryAlgorithmRows(final MCPFeatureQueryFacade queryFacade) {
         try {
-            return queryFacade.queryWithAnyDatabase("SHOW MASK ALGORITHM PLUGINS");
+            return WorkflowQueryResult.confirmed(queryFacade.queryWithAnyDatabase("SHOW MASK ALGORITHM PLUGINS"));
         } catch (final MCPQueryFailedException ex) {
             if (WorkflowDistSQLQueryUtils.isUnsupportedDistSQLQueryFailure(ex)) {
-                return propertyTemplateService.getSupportedAlgorithmTypes().stream().map(each -> Map.<String, Object>of("type", each)).toList();
+                return WorkflowQueryResult.fallback(propertyTemplateService.getSupportedAlgorithmTypes().stream().map(each -> Map.<String, Object>of("type", each)).toList());
             }
             throw ex;
         }
diff --git a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningService.java b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningService.java
index 74d5f1ce359..6d4f9ee8983 100644
--- a/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningService.java
+++ b/mcp/features/mask/src/main/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningService.java
@@ -29,6 +29,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnaps
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowLifecycle;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowRequest;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowPlanningSupport;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowRuleValueUtils;
@@ -170,7 +171,7 @@ public final class MaskWorkflowPlanningService {
     }
     
     private void planAlgorithms(final MCPFeatureQueryFacade queryFacade, final ClarifiedIntent clarifiedIntent, final WorkflowRequest request, final WorkflowContextSnapshot snapshot) {
-        List<Map<String, Object>> maskAlgorithms = ruleInspectionService.queryMaskAlgorithms(queryFacade);
+        WorkflowQueryResult maskAlgorithms = ruleInspectionService.queryMaskAlgorithms(queryFacade);
         List<AlgorithmCandidate> algorithmCandidates = algorithmRecommendationService.recommendMaskAlgorithms(clarifiedIntent, request, maskAlgorithms, snapshot.getIssues());
         snapshot.getAlgorithmCandidates().addAll(algorithmCandidates);
         if (!algorithmCandidates.isEmpty()) {
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandlerTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandlerTest.java
index 757e1f844e4..6a5b6efeb7c 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandlerTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskAlgorithmsHandlerTest.java
@@ -22,6 +22,7 @@ import org.apache.shardingsphere.mcp.api.capability.resource.MCPResourceURIVaria
 import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskRuleInspectionService;
 import org.apache.shardingsphere.mcp.support.MCPFeatureRequestContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.junit.jupiter.api.Test;
 import org.mockito.MockedConstruction;
 
@@ -45,7 +46,7 @@ class MaskAlgorithmsHandlerTest {
         when(requestContext.getQueryFacade()).thenReturn(queryFacade);
         try (
                 MockedConstruction<MaskRuleInspectionService> mockedConstruction = mockConstruction(MaskRuleInspectionService.class,
-                        (mock, context) -> when(mock.queryMaskAlgorithms(queryFacade)).thenReturn(List.of(Map.of("type", "MD5"))))) {
+                        (mock, context) -> when(mock.queryMaskAlgorithms(queryFacade)).thenReturn(WorkflowQueryResult.confirmed(List.of(Map.of("type", "MD5")))))) {
             MCPSuccessPayload actual = new MaskAlgorithmsHandler().handle(requestContext, new MCPResourceURIVariables(Map.of()));
             verify(mockedConstruction.constructed().getFirst()).queryMaskAlgorithms(queryFacade);
             assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationServiceTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationServiceTest.java
index 6972988f77a..46b210c716a 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationServiceTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskAlgorithmRecommendationServiceTest.java
@@ -21,6 +21,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.AlgorithmCandidate;
 import org.apache.shardingsphere.mcp.support.workflow.model.ClarifiedIntent;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowRequest;
 import org.junit.jupiter.api.Test;
 
@@ -41,7 +42,7 @@ class MaskAlgorithmRecommendationServiceTest {
         WorkflowRequest request = new WorkflowRequest();
         request.setAlgorithmType("MD5");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(new ClarifiedIntent(), request, List.of(Map.of("type", "MD5")), issues);
+        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(new ClarifiedIntent(), request, confirmed(Map.of("type", "MD5")), issues);
         assertThat(actual.size(), is(1));
         assertThat(actual.get(0).getAlgorithmType(), is("MD5"));
         assertTrue(issues.isEmpty());
@@ -52,7 +53,7 @@ class MaskAlgorithmRecommendationServiceTest {
         WorkflowRequest request = new WorkflowRequest();
         request.setAlgorithmType("CUSTOM");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(new ClarifiedIntent(), request, List.of(Map.of("type", "MD5")), issues);
+        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(new ClarifiedIntent(), request, confirmed(Map.of("type", "MD5")), issues);
         assertTrue(actual.isEmpty());
         assertThat(issues.get(0).getCode(), is(WorkflowIssueCode.ALGORITHM_NOT_FOUND));
     }
@@ -63,7 +64,7 @@ class MaskAlgorithmRecommendationServiceTest {
         clarifiedIntent.setFieldSemantics("phone");
         WorkflowRequest request = new WorkflowRequest();
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(clarifiedIntent, request, List.of(
+        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(clarifiedIntent, request, confirmed(
                 Map.of("type", "MASK_FROM_X_TO_Y"),
                 Map.of("type", "KEEP_FIRST_N_LAST_M")), issues);
         assertThat(actual.size(), is(1));
@@ -76,7 +77,7 @@ class MaskAlgorithmRecommendationServiceTest {
         WorkflowRequest request = new WorkflowRequest();
         request.setNaturalLanguageIntent("保留前3后4位");
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(clarifiedIntent, request, List.of(
+        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(clarifiedIntent, request, confirmed(
                 Map.of("type", "MASK_FROM_X_TO_Y"),
                 Map.of("type", "KEEP_FIRST_N_LAST_M")), issues);
         assertThat(actual.size(), is(1));
@@ -86,8 +87,24 @@ class MaskAlgorithmRecommendationServiceTest {
     @Test
     void assertRecommendMaskAlgorithmsWithoutAvailableAlgorithms() {
         List<WorkflowIssue> issues = new LinkedList<>();
-        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(new ClarifiedIntent(), new WorkflowRequest(), List.of(), issues);
+        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(
+                new ClarifiedIntent(), new WorkflowRequest(), WorkflowQueryResult.confirmed(List.of()), issues);
         assertTrue(actual.isEmpty());
         assertThat(issues.get(0).getCode(), is(WorkflowIssueCode.ALGORITHM_NOT_FOUND));
     }
+    
+    @Test
+    void assertRecommendMaskAlgorithmsWithUnconfirmedAvailability() {
+        WorkflowRequest request = new WorkflowRequest();
+        request.setAlgorithmType("CUSTOM");
+        List<WorkflowIssue> issues = new LinkedList<>();
+        List<AlgorithmCandidate> actual = service.recommendMaskAlgorithms(new ClarifiedIntent(), request, WorkflowQueryResult.fallback(List.of()), issues);
+        assertThat(actual.getFirst().getAlgorithmType(), is("CUSTOM"));
+        assertTrue(issues.isEmpty());
+    }
+    
+    @SafeVarargs
+    private WorkflowQueryResult confirmed(final Map<String, Object>... rows) {
+        return WorkflowQueryResult.confirmed(List.of(rows));
+    }
 }
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionServiceTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionServiceTest.java
index bb7698be5d8..5a6251016c5 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionServiceTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskRuleInspectionServiceTest.java
@@ -20,6 +20,7 @@ package org.apache.shardingsphere.mcp.feature.mask.tool.service;
 import org.apache.shardingsphere.mcp.api.exception.MCPInvalidRequestException;
 import org.apache.shardingsphere.mcp.api.exception.MCPQueryFailedException;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.junit.jupiter.api.Test;
 
 import java.sql.SQLException;
@@ -29,6 +30,7 @@ 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.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -102,14 +104,15 @@ class MaskRuleInspectionServiceTest {
     void assertQueryMaskAlgorithms() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         when(queryFacade.queryWithAnyDatabase("SHOW MASK ALGORITHM PLUGINS")).thenReturn(List.of(Map.of("type", "MASK_FROM_X_TO_Y"), Map.of("type", "CUSTOM")));
-        List<Map<String, Object>> actual = service.queryMaskAlgorithms(queryFacade);
-        assertThat(actual.getFirst().get("type"), is("MASK_FROM_X_TO_Y"));
-        assertThat(actual.getFirst().get("required_properties"), is(List.of("from-x", "to-y", "replace-char")));
-        assertThat(actual.getFirst().get("optional_properties"), is(List.of()));
-        List<?> propertyTemplates = (List<?>) actual.get(0).get("property_templates");
+        WorkflowQueryResult actual = service.queryMaskAlgorithms(queryFacade);
+        assertThat(actual.getRows().getFirst().get("type"), is("MASK_FROM_X_TO_Y"));
+        assertThat(actual.getRows().getFirst().get("required_properties"), is(List.of("from-x", "to-y", "replace-char")));
+        assertThat(actual.getRows().getFirst().get("optional_properties"), is(List.of()));
+        List<?> propertyTemplates = (List<?>) actual.getRows().getFirst().get("property_templates");
         assertThat(((Map<?, ?>) propertyTemplates.getFirst()).get("property_key"), is("from-x"));
-        assertThat(actual.get(1).get("type"), is("CUSTOM"));
-        assertThat(actual.get(1).get("property_templates"), is(List.of()));
+        assertThat(actual.getRows().get(1).get("type"), is("CUSTOM"));
+        assertThat(actual.getRows().get(1).get("property_templates"), is(List.of()));
+        assertTrue(actual.isAvailabilityConfirmed());
     }
     
     @Test
@@ -117,9 +120,10 @@ class MaskRuleInspectionServiceTest {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         when(queryFacade.queryWithAnyDatabase("SHOW MASK ALGORITHM PLUGINS"))
                 .thenThrow(new MCPQueryFailedException("syntax error near 'MASK ALGORITHM PLUGINS'", new SQLSyntaxErrorException("syntax error")));
-        List<Map<String, Object>> actual = service.queryMaskAlgorithms(queryFacade);
-        assertThat(actual.getFirst().get("type"), is("KEEP_FIRST_N_LAST_M"));
-        assertThat(actual.getFirst().get("required_properties"), is(List.of("first-n", "last-m", "replace-char")));
+        WorkflowQueryResult actual = service.queryMaskAlgorithms(queryFacade);
+        assertThat(actual.getRows().getFirst().get("type"), is("KEEP_FIRST_N_LAST_M"));
+        assertThat(actual.getRows().getFirst().get("required_properties"), is(List.of("first-n", "last-m", "replace-char")));
+        assertFalse(actual.isAvailabilityConfirmed());
     }
     
     @Test
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningServiceTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningServiceTest.java
index 363de26165c..2f34f988112 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningServiceTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowPlanningServiceTest.java
@@ -41,6 +41,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnaps
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowFieldNames;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssue;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowIssueCode;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowQueryResult;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowRequest;
 import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowPlanPayloadBuilder;
 import org.junit.jupiter.api.AfterEach;
@@ -140,7 +141,7 @@ class MaskWorkflowPlanningServiceTest {
     void assertPlanRejectsAddingColumnToExistingTableRule() {
         MaskRuleInspectionService ruleInspectionService = mock(MaskRuleInspectionService.class);
         when(ruleInspectionService.queryMaskRules(any(), any(), any())).thenReturn(List.of(Map.of("column", "phone", "algorithm_type", "MD5")));
-        when(ruleInspectionService.queryMaskAlgorithms(any())).thenReturn(List.of());
+        when(ruleInspectionService.queryMaskAlgorithms(any())).thenReturn(WorkflowQueryResult.confirmed(List.of()));
         WorkflowRequest request = createRequest("create");
         request.setColumn("amount");
         request.getPrimaryAlgorithmProperties().put("from-x", "1");
@@ -200,7 +201,7 @@ class MaskWorkflowPlanningServiceTest {
                                                 final String expectedStatus) {
         MaskRuleInspectionService ruleInspectionService = mock(MaskRuleInspectionService.class);
         when(ruleInspectionService.queryMaskRules(any(), any(), any())).thenReturn(ruleExists ? List.of(Map.of("column", "phone")) : List.of());
-        when(ruleInspectionService.queryMaskAlgorithms(any())).thenReturn(List.of(Map.of("type", "MASK_FROM_X_TO_Y")));
+        when(ruleInspectionService.queryMaskAlgorithms(any())).thenReturn(WorkflowQueryResult.confirmed(List.of(Map.of("type", "MASK_FROM_X_TO_Y"))));
         WorkflowContextSnapshot actual = createService(ruleInspectionService, new MaskAlgorithmRecommendationService(), new MaskAlgorithmPropertyTemplateService(),
                 new MaskRuleDistSQLPlanningService()).plan(new TestWorkflowSessionContext(), createMetadataQueryFacade(), createQueryFacade(),
                         createNaturalLanguageRequest(naturalLanguageIntent));
@@ -216,7 +217,7 @@ class MaskWorkflowPlanningServiceTest {
     void assertPlanStopsOnBlockingAlgorithmIssue() {
         MaskRuleInspectionService ruleInspectionService = mock(MaskRuleInspectionService.class);
         when(ruleInspectionService.queryMaskRules(any(), any(), any())).thenReturn(List.of());
-        when(ruleInspectionService.queryMaskAlgorithms(any())).thenReturn(List.of());
+        when(ruleInspectionService.queryMaskAlgorithms(any())).thenReturn(WorkflowQueryResult.confirmed(List.of()));
         MaskAlgorithmRecommendationService algorithmRecommendationService = mock(MaskAlgorithmRecommendationService.class);
         when(algorithmRecommendationService.recommendMaskAlgorithms(any(), any(), any(), any())).thenAnswer(invocation -> {
             List<WorkflowIssue> issues = invocation.getArgument(3);
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 b7065ccd822..f43c029a495 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
@@ -125,7 +125,7 @@ resourceTemplates:
           required: true
           scope: logical-database
       resourceKind: list
-      objectScope: rule
+      objectScope: algorithm
       feature: shadow
       relatedTools:
         - database_gateway_plan_default_shadow_algorithm
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 c5075e95974..f602a6d866d 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
@@ -21,6 +21,7 @@ import org.apache.shardingsphere.mcp.api.capability.tool.MCPToolDescriptor;
 import org.apache.shardingsphere.mcp.api.capability.completion.MCPCompletionTargetDescriptor;
 import org.apache.shardingsphere.mcp.support.descriptor.MCPDescriptorCatalog;
 import org.apache.shardingsphere.mcp.support.descriptor.MCPDescriptorCatalogLoader;
+import org.apache.shardingsphere.mcp.support.descriptor.ShardingSphereMCPResourceMetadata;
 import org.junit.jupiter.api.Test;
 
 import java.util.List;
@@ -61,10 +62,20 @@ class ShadowDescriptorContractTest {
         assertThat(((Map<String, Object>) structuredIntentProperties.get("algorithm_type")).get("enum"), is(List.of("SQL_HINT")));
     }
     
+    @Test
+    void assertAlgorithmResourceScope() {
+        MCPDescriptorCatalog catalog = MCPDescriptorCatalogLoader.load();
+        assertThat(findResourceMetadata(catalog, "shardingsphere://features/shadow/databases/{database}/algorithms").getObjectScope(), is("algorithm"));
+    }
+    
     private MCPToolDescriptor findTool(final MCPDescriptorCatalog catalog, final String toolName) {
         return catalog.getProtocolDescriptors().getToolDescriptors().stream().filter(each -> toolName.equals(each.getName())).findFirst().orElseThrow();
     }
     
+    private ShardingSphereMCPResourceMetadata findResourceMetadata(final MCPDescriptorCatalog catalog, final String uriTemplate) {
+        return catalog.getShardingSphereDescriptors().getResourceMetadata().stream().filter(each -> uriTemplate.equals(each.getUriTemplate())).findFirst().orElseThrow();
+    }
+    
     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();
diff --git a/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationService.java b/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationService.java
index 306c3a340c1..5b68ec393d2 100644
--- a/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationService.java
+++ b/mcp/features/sharding/src/main/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationService.java
@@ -266,7 +266,7 @@ public final class ShardingWorkflowValidationService implements MCPWorkflowRunti
     }
     
     private List<Map<String, Object>> queryCleanupRows(final MCPFeatureQueryFacade queryFacade, final ShardingWorkflowRequest request) {
-        switch (request.getComponentType().toLowerCase().replace('_', '-')) {
+        switch (request.getComponentType().toLowerCase(Locale.ENGLISH).replace('_', '-')) {
             case "algorithm":
                 return inspectionService.queryAlgorithms(queryFacade, request.getDatabase());
             case "key-generator":
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 e0d6817ca9e..d12185c12ca 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
@@ -49,16 +49,18 @@ resourceTemplates:
     title: Sharding Algorithms
     description: "List configured sharding algorithms for one logical database."
     mimeType: application/json
-    shardingSphereMetadata: &databaseListMetadata
-      uriVariables:
-        - name: database
-          title: Logical Database
-          description: "ShardingSphere logical database."
-          required: true
-          scope: logical-database
-      resourceKind: list
-      objectScope: rule
-      feature: sharding
+    shardingSphereMetadata:
+      <<: &databaseListMetadata
+        uriVariables:
+          - name: database
+            title: Logical Database
+            description: "ShardingSphere logical database."
+            required: true
+            scope: logical-database
+        resourceKind: list
+        objectScope: rule
+        feature: sharding
+      objectScope: algorithm
       relatedTools:
         - database_gateway_plan_sharding_table_rule
         - database_gateway_plan_sharding_default_strategy
@@ -237,6 +239,7 @@ resourceTemplates:
     mimeType: application/json
     shardingSphereMetadata:
       <<: *databaseListMetadata
+      objectScope: algorithm
       relatedTools:
         - database_gateway_plan_sharding_rule_component_cleanup
   - uriTemplate: shardingsphere://features/sharding/databases/{database}/unused-key-generators
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 2ea4410c8c9..12ef1a2670e 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
@@ -22,6 +22,7 @@ import org.apache.shardingsphere.mcp.api.capability.tool.MCPToolDescriptor;
 import org.apache.shardingsphere.mcp.api.capability.completion.MCPCompletionTargetDescriptor;
 import org.apache.shardingsphere.mcp.support.descriptor.MCPDescriptorCatalog;
 import org.apache.shardingsphere.mcp.support.descriptor.MCPDescriptorCatalogLoader;
+import org.apache.shardingsphere.mcp.support.descriptor.ShardingSphereMCPResourceMetadata;
 import org.junit.jupiter.api.Test;
 
 import java.util.List;
@@ -83,6 +84,13 @@ class ShardingDescriptorContractTest {
         assertOperationTypeEnum(findTool(catalog, ShardingFeatureDefinition.PLAN_COMPONENT_CLEANUP_TOOL_NAME), List.of("drop"));
     }
     
+    @Test
+    void assertAlgorithmResourceScopes() {
+        MCPDescriptorCatalog catalog = MCPDescriptorCatalogLoader.load();
+        assertThat(findResourceMetadata(catalog, "shardingsphere://features/sharding/databases/{database}/algorithms").getObjectScope(), is("algorithm"));
+        assertThat(findResourceMetadata(catalog, "shardingsphere://features/sharding/databases/{database}/unused-algorithms").getObjectScope(), is("algorithm"));
+    }
+    
     private MCPPromptDescriptor findPrompt(final MCPDescriptorCatalog catalog, final String promptName) {
         return catalog.getProtocolDescriptors().getPromptDescriptors().stream().filter(each -> promptName.equals(each.getName())).findFirst().orElseThrow();
     }
@@ -91,6 +99,10 @@ class ShardingDescriptorContractTest {
         return catalog.getProtocolDescriptors().getToolDescriptors().stream().filter(each -> toolName.equals(each.getName())).findFirst().orElseThrow();
     }
     
+    private ShardingSphereMCPResourceMetadata findResourceMetadata(final MCPDescriptorCatalog catalog, final String uriTemplate) {
+        return catalog.getShardingSphereDescriptors().getResourceMetadata().stream().filter(each -> uriTemplate.equals(each.getUriTemplate())).findFirst().orElseThrow();
+    }
+    
     private void assertOperationTypeEnum(final MCPToolDescriptor descriptor, final List<String> expectedValues) {
         Map<?, ?> properties = (Map<?, ?>) descriptor.getInputSchema().get("properties");
         Map<?, ?> operationType = (Map<?, ?>) properties.get("operation_type");
diff --git a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/handler/ShardingWorkflowToolHandlersTest.java b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/handler/ShardingWorkflowToolHandlersTest.java
index 1b4200eb63a..bc616644fc1 100644
--- a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/handler/ShardingWorkflowToolHandlersTest.java
+++ b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/handler/ShardingWorkflowToolHandlersTest.java
@@ -38,6 +38,7 @@ import org.mockito.MockedConstruction;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -169,8 +170,14 @@ class ShardingWorkflowToolHandlersTest {
                     "shardingsphere://features/sharding/databases/logic_db/unused-algorithms",
                     "shardingsphere://features/sharding/databases/logic_db/unused-key-generators",
                     "shardingsphere://features/sharding/databases/logic_db/unused-auditors")));
-            for (String each : actualResourceUris) {
-                assertThat(findResourceKind(actualResourcesToRead, each), is("rule"));
+            for (Entry<String, String> entry : Map.of(
+                    "shardingsphere://features/sharding/databases/logic_db/algorithms", "algorithm",
+                    "shardingsphere://features/sharding/databases/logic_db/key-generators", "rule",
+                    "shardingsphere://features/sharding/databases/logic_db/auditors", "rule",
+                    "shardingsphere://features/sharding/databases/logic_db/unused-algorithms", "algorithm",
+                    "shardingsphere://features/sharding/databases/logic_db/unused-key-generators", "rule",
+                    "shardingsphere://features/sharding/databases/logic_db/unused-auditors", "rule").entrySet()) {
+                assertThat(findResourceKind(actualResourcesToRead, entry.getKey()), is(entry.getValue()));
             }
         }
     }
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 e45d567ca0f..404abb99b5e 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
@@ -23,12 +23,14 @@ import org.apache.shardingsphere.mcp.api.capability.completion.MCPCompletionTarg
 import org.apache.shardingsphere.mcp.api.capability.prompt.MCPPromptDescriptor;
 import org.apache.shardingsphere.mcp.api.capability.resource.MCPResourceDescriptor;
 import org.apache.shardingsphere.mcp.api.capability.tool.MCPToolDescriptor;
+import org.apache.shardingsphere.mcp.support.resource.MCPUriTemplate;
 
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
@@ -45,6 +47,8 @@ public final class MCPDescriptorCatalogIndex {
     
     private static final Map<String, ShardingSphereMCPResourceMetadata> SHARDINGSPHERE_RESOURCE_METADATA = createShardingSphereResourceMetadata();
     
+    private static final List<Entry<MCPUriTemplate, ShardingSphereMCPResourceMetadata>> RESOURCE_METADATA_TEMPLATES = createResourceMetadataTemplates();
+    
     private static final Map<String, MCPToolDescriptor> TOOL_DESCRIPTORS = createToolDescriptors();
     
     private static final Collection<MCPPromptDescriptor> PROMPT_DESCRIPTORS = CATALOG.getProtocolDescriptors().getPromptDescriptors();
@@ -78,6 +82,10 @@ public final class MCPDescriptorCatalogIndex {
                 .collect(Collectors.toMap(ShardingSphereMCPResourceMetadata::getUriTemplate, each -> each));
     }
     
+    private static List<Entry<MCPUriTemplate, ShardingSphereMCPResourceMetadata>> createResourceMetadataTemplates() {
+        return CATALOG.getShardingSphereDescriptors().getResourceMetadata().stream().map(each -> Map.entry(new MCPUriTemplate(each.getUriTemplate()), each)).toList();
+    }
+    
     private static Map<String, MCPToolDescriptor> createToolDescriptors() {
         return CATALOG.getProtocolDescriptors().getToolDescriptors().stream()
                 .collect(Collectors.toMap(MCPToolDescriptor::getName, each -> each, (a, b) -> b, () -> new LinkedHashMap<>(CATALOG.getProtocolDescriptors().getToolDescriptors().size(), 1F)));
@@ -185,6 +193,24 @@ public final class MCPDescriptorCatalogIndex {
                 () -> new IllegalStateException(String.format("ShardingSphere MCP resource metadata descriptor is required for `%s`.", uriTemplate)));
     }
     
+    /**
+     * Resolve resource kind from a descriptor URI template or expanded resource URI.
+     *
+     * @param uri resource URI or URI template
+     * @return descriptor resource kind, or generic resource kind when the URI is unknown
+     */
+    public static String resolveResourceKind(final String uri) {
+        ShardingSphereMCPResourceMetadata metadata = SHARDINGSPHERE_RESOURCE_METADATA.get(uri);
+        if (null == metadata) {
+            metadata = RESOURCE_METADATA_TEMPLATES.stream().filter(each -> each.getKey().parse(uri).isPresent())
+                    .map(Entry::getValue).findFirst().orElse(null);
+        }
+        if (null == metadata) {
+            return "resource";
+        }
+        return null == metadata.getObjectScope() ? metadata.getResourceKind() : metadata.getObjectScope();
+    }
+    
     /**
      * Get tool descriptors.
      *
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogYamlSwapper.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogYamlSwapper.java
index 421696266cf..b2e82cb1a7f 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogYamlSwapper.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorCatalogYamlSwapper.java
@@ -194,7 +194,7 @@ final class MCPDescriptorCatalogYamlSwapper {
     }
     
     private static MCPToolRuntimeDescriptor swapToolRuntimeDescriptor(final String toolName, final YamlMCPToolRuntimeDescriptor yamlRuntime) {
-        return new MCPToolRuntimeDescriptor(toolName, null == yamlRuntime.getWorkflowRole() ? "" : yamlRuntime.getWorkflowRole(), emptyIfNull(yamlRuntime.getSideEffectScope()));
+        return new MCPToolRuntimeDescriptor(toolName, null == yamlRuntime.getWorkflowRole() ? "" : yamlRuntime.getWorkflowRole());
     }
     
     private static <T> Collection<T> emptyIfNull(final Collection<T> values) {
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorYamlKeyValidator.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorYamlKeyValidator.java
index 3a095ca42cc..0e1030eb666 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorYamlKeyValidator.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPDescriptorYamlKeyValidator.java
@@ -48,7 +48,7 @@ final class MCPDescriptorYamlKeyValidator {
     
     private static final Collection<String> REQUIRED_TOOL_ANNOTATION_HINT_KEYS = Set.of("readOnlyHint", "destructiveHint", "idempotentHint", "openWorldHint");
     
-    private static final Collection<String> TOOL_RUNTIME_KEYS = Set.of("workflowRole", "sideEffectScope");
+    private static final Collection<String> TOOL_RUNTIME_KEYS = Set.of("workflowRole");
     
     private static final Collection<String> PROMPT_KEYS = Set.of("name", "title", "description", "arguments", "binding", "meta");
     
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 47dc80d6be4..57d6de6e0a6 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
@@ -19,9 +19,11 @@ package org.apache.shardingsphere.mcp.support.descriptor;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.mcp.support.protocol.MCPModelFacingPayloadContract;
 import org.apache.shardingsphere.mcp.support.protocol.MCPResponseMode;
 import org.apache.shardingsphere.mcp.support.security.MCPClientSafetyPolicy;
 
+import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -76,18 +78,11 @@ final class MCPGuidancePayloadBuilder {
     
     static List<Map<String, Object>> createNextActionContract() {
         return List.of(
-                createNextActionContractEntry("resource_read", List.of("order", "type", "title", "resource_uri"),
-                        List.of("reason", "depends_on"), "Read an MCP resource before choosing another call."),
-                createNextActionContractEntry("tool_call", List.of("order", "type", "title", "tool_name", "arguments"),
-                        List.of("reason", "depends_on"), "Call another MCP tool with server-suggested arguments."),
-                createNextActionContractEntry("completion",
-                        List.of("order", "type", "title", "ref", "argument"),
-                        List.of("context", "missing_context_arguments", "resume_ref", "resume_arguments", "reason", "depends_on"),
-                        "Use MCP completion for one argument before retrying."),
-                createNextActionContractEntry("ask_user", List.of("order", "type", "title", "question"),
-                        List.of("required_inputs", "depends_on"), "Ask the user for missing input."),
-                createNextActionContractEntry("terminal", List.of("order", "type", "title"),
-                        List.of("reason", "depends_on"), "Stop the current MCP flow and report the result."));
+                createNextActionContractEntry("resource_read", "Read an MCP resource before choosing another call."),
+                createNextActionContractEntry("tool_call", "Call another MCP tool with server-suggested arguments."),
+                createNextActionContractEntry("completion", "Use MCP completion for one argument before retrying."),
+                createNextActionContractEntry("ask_user", "Ask the user for missing input."),
+                createNextActionContractEntry("terminal", "Stop the current MCP flow and report the result."));
     }
     
     static List<Map<String, Object>> createCommonFlows() {
@@ -135,7 +130,9 @@ final class MCPGuidancePayloadBuilder {
         return result;
     }
     
-    private static Map<String, Object> createNextActionContractEntry(final String actionType, final List<String> requiredFields, final List<String> optionalFields, final String description) {
+    private static Map<String, Object> createNextActionContractEntry(final String actionType, final String description) {
+        Collection<String> requiredFields = MCPModelFacingPayloadContract.getNextActionRequiredFields(actionType);
+        List<String> optionalFields = MCPModelFacingPayloadContract.getNextActionAllowedFields(actionType).stream().filter(each -> !requiredFields.contains(each)).toList();
         Map<String, Object> result = new LinkedHashMap<>(4, 1F);
         result.put("type", actionType);
         result.put("required_fields", requiredFields);
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilder.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilder.java
index 905407d78ae..a98b935b5c0 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilder.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilder.java
@@ -57,7 +57,7 @@ public final class MCPResourceNavigationPayloadBuilder {
     public static Map<String, Object> create(final MCPResourceDescriptor descriptor, final MCPResourceURIVariables uriVariables, final String parentUriTemplate) {
         Map<String, Object> result = new LinkedHashMap<>(2, 1F);
         new MCPUriTemplate(descriptor.getUriTemplate()).expandIfComplete(uriVariables)
-                .ifPresent(optional -> result.put(MCPPayloadFieldNames.SELF_RESOURCE, MCPResourceHintUtils.create(optional, resolveResourceKind(optional), "inspect_self",
+                .ifPresent(optional -> result.put(MCPPayloadFieldNames.SELF_RESOURCE, MCPResourceHintUtils.create(optional, MCPDescriptorCatalogIndex.resolveResourceKind(optional), "inspect_self",
                         "Read this resource.", MCPPayloadFieldNames.SELF_RESOURCE)));
         if (!parentUriTemplate.isEmpty()) {
             Optional<String> parentUri = new MCPUriTemplate(parentUriTemplate).expandIfComplete(uriVariables);
@@ -67,22 +67,6 @@ public final class MCPResourceNavigationPayloadBuilder {
     }
     
     private static Map<String, Object> createParentResourceHint(final String uri) {
-        return MCPResourceHintUtils.create(uri, resolveResourceKind(uri), "inspect_parent", "Read the parent resource.", MCPPayloadFieldNames.PARENT_RESOURCE);
-    }
-    
-    private static String resolveResourceKind(final String uri) {
-        if (uri.contains("/rules")) {
-            return "rule";
-        }
-        if (uri.contains("/algorithms")) {
-            return "algorithm";
-        }
-        if (uri.contains("/columns")) {
-            return "column";
-        }
-        if (uri.contains("/indexes")) {
-            return "index";
-        }
-        return "resource";
+        return MCPResourceHintUtils.create(uri, MCPDescriptorCatalogIndex.resolveResourceKind(uri), "inspect_parent", "Read the parent resource.", MCPPayloadFieldNames.PARENT_RESOURCE);
     }
 }
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 7f71bb1009d..cb38478ca7c 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
@@ -53,9 +53,6 @@ public final class MCPToolDescriptorCatalogValidator {
     
     private static final Collection<String> SECRET_WORKFLOW_OUTPUT_FIELDS = List.of("masked_property_preview", "secret_reference_summary");
     
-    private static final Collection<String> SUPPORTED_SIDE_EFFECT_SCOPES = Set.of(
-            "physical-data", "physical-structure", "privilege-metadata", "rule-metadata", "transaction-state");
-    
     /**
      * Validate tool descriptors in one descriptor catalog.
      *
@@ -77,7 +74,7 @@ public final class MCPToolDescriptorCatalogValidator {
             MCPToolInputSchemaValidator.validate(each);
             MCPToolOutputSchemaValidator.validate(each);
             validateToolDescriptorContract(each, runtimes.get(each.getName()));
-            validateDestructiveToolDescriptor(each, runtimes.get(each.getName()));
+            validateDestructiveToolDescriptor(each);
             validateNonDestructiveExecutionMode(each);
             validateRelatedResourceUris(each, resourceIdentifiers, shardingSphereResourceIdentifiers);
         }
@@ -88,10 +85,6 @@ public final class MCPToolDescriptorCatalogValidator {
         for (MCPToolRuntimeDescriptor each : runtimeDescriptors) {
             ShardingSpherePreconditions.checkState(each.getWorkflowRole().isBlank() || "plan".equals(each.getWorkflowRole()),
                     () -> new IllegalStateException(String.format("Tool `%s` runtime workflowRole `%s` is unsupported.", each.getToolName(), each.getWorkflowRole())));
-            for (String eachScope : each.getSideEffectScope()) {
-                ShardingSpherePreconditions.checkState(SUPPORTED_SIDE_EFFECT_SCOPES.contains(eachScope),
-                        () -> new IllegalStateException(String.format("Tool `%s` runtime sideEffectScope `%s` is unsupported.", each.getToolName(), eachScope)));
-            }
         }
     }
     
@@ -293,7 +286,7 @@ public final class MCPToolDescriptorCatalogValidator {
                 () -> new IllegalStateException(String.format("Planning tool `%s` annotations.idempotentHint must be false.", descriptor.getName())));
     }
     
-    private static void validateDestructiveToolDescriptor(final MCPToolDescriptor descriptor, final MCPToolRuntimeDescriptor runtimeDescriptor) {
+    private static void validateDestructiveToolDescriptor(final MCPToolDescriptor descriptor) {
         if (!descriptor.getAnnotations().isDestructiveHint()) {
             return;
         }
@@ -306,8 +299,6 @@ public final class MCPToolDescriptorCatalogValidator {
                 () -> new IllegalStateException(String.format("Destructive tool `%s` execution_mode must allow preview.", descriptor.getName())));
         ShardingSpherePreconditions.checkState(!executionModes.contains("auto-execute"),
                 () -> new IllegalStateException(String.format("Destructive tool `%s` execution_mode must not expose auto-execute.", descriptor.getName())));
-        ShardingSpherePreconditions.checkState(null != runtimeDescriptor && !runtimeDescriptor.getSideEffectScope().isEmpty(),
-                () -> new IllegalStateException(String.format("Destructive tool `%s` must declare sideEffectScope in internal runtime.", descriptor.getName())));
     }
     
     private static void validateNonDestructiveExecutionMode(final MCPToolDescriptor descriptor) {
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolRuntimeDescriptor.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolRuntimeDescriptor.java
index d2c9139fd4b..646bef62dbd 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolRuntimeDescriptor.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/MCPToolRuntimeDescriptor.java
@@ -20,8 +20,6 @@ package org.apache.shardingsphere.mcp.support.descriptor;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 
-import java.util.Collection;
-
 /**
  * MCP tool runtime descriptor.
  */
@@ -32,6 +30,4 @@ public final class MCPToolRuntimeDescriptor {
     private final String toolName;
     
     private final String workflowRole;
-    
-    private final Collection<String> sideEffectScope;
 }
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/yaml/YamlMCPToolRuntimeDescriptor.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/yaml/YamlMCPToolRuntimeDescriptor.java
index f3b500a9d9d..e25d0f14950 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/yaml/YamlMCPToolRuntimeDescriptor.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/descriptor/yaml/YamlMCPToolRuntimeDescriptor.java
@@ -20,9 +20,6 @@ package org.apache.shardingsphere.mcp.support.descriptor.yaml;
 import lombok.Getter;
 import lombok.Setter;
 
-import java.util.Collection;
-import java.util.LinkedList;
-
 /**
  * YAML MCP tool runtime descriptor.
  */
@@ -31,6 +28,4 @@ import java.util.LinkedList;
 public final class YamlMCPToolRuntimeDescriptor {
     
     private String workflowRole;
-    
-    private Collection<String> sideEffectScope = new LinkedList<>();
 }
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContract.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContract.java
index 795495755f4..a333e620e0d 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContract.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContract.java
@@ -37,18 +37,18 @@ public final class MCPModelFacingPayloadContract {
             "recommended_recovery", "suggested_next_action", "approved_by_user", "requires_user_approval", "approval_required", "user_overrides");
     
     private static final Map<String, Collection<String>> NEXT_ACTION_REQUIRED_FIELDS = Map.of(
-            "resource_read", Set.of("order", "type", "title", "resource_uri"),
-            "tool_call", Set.of("order", "type", "title", "tool_name", "arguments"),
-            "completion", Set.of("order", "type", "title", "ref", "argument"),
-            "ask_user", Set.of("order", "type", "title", "question"),
-            "terminal", Set.of("order", "type", "title"));
+            "resource_read", List.of("order", "type", "title", "resource_uri"),
+            "tool_call", List.of("order", "type", "title", "tool_name", "arguments"),
+            "completion", List.of("order", "type", "title", "ref", "argument"),
+            "ask_user", List.of("order", "type", "title", "question"),
+            "terminal", List.of("order", "type", "title"));
     
     private static final Map<String, Collection<String>> NEXT_ACTION_ALLOWED_FIELDS = Map.of(
-            "resource_read", Set.of("order", "type", "title", "resource_uri", "reason", "depends_on"),
-            "tool_call", Set.of("order", "type", "title", "tool_name", "arguments", "reason", "depends_on"),
-            "completion", Set.of("order", "type", "title", "ref", "argument", "context", "missing_context_arguments", "resume_ref", "resume_arguments", "reason", "depends_on"),
-            "ask_user", Set.of("order", "type", "title", "question", "required_inputs", "depends_on"),
-            "terminal", Set.of("order", "type", "title", "reason", "depends_on"));
+            "resource_read", List.of("order", "type", "title", "resource_uri", "reason", "depends_on"),
+            "tool_call", List.of("order", "type", "title", "tool_name", "arguments", "reason", "depends_on"),
+            "completion", List.of("order", "type", "title", "ref", "argument", "context", "missing_context_arguments", "resume_ref", "resume_arguments", "reason", "depends_on"),
+            "ask_user", List.of("order", "type", "title", "question", "required_inputs", "depends_on"),
+            "terminal", List.of("order", "type", "title", "reason", "depends_on"));
     
     private static final Collection<String> NEXT_ACTION_SCHEMA_ALLOWED_FIELDS = createNextActionSchemaAllowedFields();
     
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/SecretReferenceValue.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/SecretReferenceValue.java
index a52c3ec45c6..949b6ac3a17 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/SecretReferenceValue.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/SecretReferenceValue.java
@@ -22,6 +22,7 @@ import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 
 import java.util.LinkedHashMap;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -96,7 +97,7 @@ public final class SecretReferenceValue {
     }
     
     private static String normalizeForManualPlaceholder(final String value) {
-        String result = normalize(value).toUpperCase().replaceAll("[^A-Z0-9]+", "_");
+        String result = normalize(value).toUpperCase(Locale.ENGLISH).replaceAll("[^A-Z0-9]+", "_");
         return result.isEmpty() ? "VALUE" : result;
     }
 }
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowContextSnapshot.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowContextSnapshot.java
index 678e1384a53..a0fd5a39b75 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowContextSnapshot.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowContextSnapshot.java
@@ -88,7 +88,7 @@ public final class WorkflowContextSnapshot {
         result.setWorkflowKind(workflowKind);
         result.setSessionId(sessionId);
         result.setStatus(status);
-        result.setUpdateTime(copyInstant(updateTime));
+        result.setUpdateTime(updateTime);
         result.setRequest(null == request ? null : request.copy());
         result.setClarifiedIntent(copyClarifiedIntent(clarifiedIntent));
         result.setFeatureData(null == featureData ? null : featureData.copy());
@@ -102,10 +102,6 @@ public final class WorkflowContextSnapshot {
         return result;
     }
     
-    private static Instant copyInstant(final Instant original) {
-        return null == original ? null : Instant.ofEpochMilli(original.toEpochMilli());
-    }
-    
     private static ClarifiedIntent copyClarifiedIntent(final ClarifiedIntent original) {
         if (null == original) {
             return null;
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowArtifactMaskUtils.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowArtifactMaskUtils.java
index 07e80f290e1..2c9ca530416 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowArtifactMaskUtils.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowArtifactMaskUtils.java
@@ -28,6 +28,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowFieldNames;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -178,7 +179,7 @@ public final class WorkflowArtifactMaskUtils {
                 return true;
             }
         }
-        String actualPropertyKey = propertyKey.toLowerCase();
+        String actualPropertyKey = propertyKey.toLowerCase(Locale.ENGLISH);
         return actualPropertyKey.contains("password") || actualPropertyKey.contains("secret") || actualPropertyKey.contains("token")
                 || "key".equals(actualPropertyKey) || actualPropertyKey.contains("-key") || actualPropertyKey.contains("key-")
                 || actualPropertyKey.contains("_key") || actualPropertyKey.contains("key_");
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidanceResourceHintProvider.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidanceResourceHintProvider.java
index c4c7c0e691a..f561da78a92 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidanceResourceHintProvider.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/service/WorkflowGuidanceResourceHintProvider.java
@@ -21,7 +21,6 @@ import org.apache.shardingsphere.mcp.api.capability.resource.MCPResourceDescript
 import org.apache.shardingsphere.mcp.api.capability.tool.MCPToolDescriptor;
 import org.apache.shardingsphere.mcp.support.descriptor.MCPDescriptorCatalogIndex;
 import org.apache.shardingsphere.mcp.support.descriptor.MCPShardingSphereMetadataKeys;
-import org.apache.shardingsphere.mcp.support.descriptor.ShardingSphereMCPResourceMetadata;
 import org.apache.shardingsphere.mcp.support.protocol.MCPPayloadFieldNames;
 import org.apache.shardingsphere.mcp.support.protocol.MCPResourceHintUtils;
 import org.apache.shardingsphere.mcp.support.resource.MCPUriPathSegmentUtils;
@@ -71,7 +70,7 @@ public final class WorkflowGuidanceResourceHintProvider {
         for (Object each : uriTemplates) {
             String uriTemplate = String.valueOf(each);
             findResourceDescriptor(uriTemplate).ifPresent(resourceDescriptor -> createConcreteResourceUri(uriTemplate, request)
-                    .ifPresent(uri -> addResourceHint(resourcesToRead, uri, resolveResourceKind(uriTemplate), resolveDescriptorResourceAction(resourceDescriptor),
+                    .ifPresent(uri -> addResourceHint(resourcesToRead, uri, MCPDescriptorCatalogIndex.resolveResourceKind(uriTemplate), resolveDescriptorResourceAction(resourceDescriptor),
                             resourceDescriptor.getDescription())));
         }
     }
@@ -101,12 +100,6 @@ public final class WorkflowGuidanceResourceHintProvider {
         return value.isEmpty() ? Optional.empty() : Optional.of(uriTemplate.replace(placeholder, MCPUriPathSegmentUtils.encodePathSegment(value)));
     }
     
-    private String resolveResourceKind(final String uriTemplate) {
-        ShardingSphereMCPResourceMetadata metadata = MCPDescriptorCatalogIndex.getRequiredShardingSphereResourceMetadata(uriTemplate);
-        String result = metadata.getObjectScope();
-        return null == result ? metadata.getResourceKind() : result;
-    }
-    
     private String resolveDescriptorResourceAction(final MCPResourceDescriptor descriptor) {
         return descriptor.isTemplated() ? "inspect_detail" : "read_first";
     }
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 93c8bbae007..377dad59350 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
@@ -371,9 +371,6 @@ tools:
       destructiveHint: true
       idempotentHint: false
       openWorldHint: true
-    runtime:
-      sideEffectScope:
-        - rule-metadata
     meta:
       org.apache.shardingsphere/follow-up-tools:
         - database_gateway_validate_workflow
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 0a9dd08e22f..3a48e2ff0f5 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
@@ -58,6 +58,16 @@ class MCPDescriptorCatalogIndexTest {
         assertThat(actual.getResourceKind(), is("detail"));
     }
     
+    @Test
+    void assertResolveResourceKind() {
+        assertThat(MCPDescriptorCatalogIndex.resolveResourceKind("shardingsphere://workflows/plan-1"), is("workflow-plan"));
+    }
+    
+    @Test
+    void assertResolveUnknownResourceKind() {
+        assertThat(MCPDescriptorCatalogIndex.resolveResourceKind("shardingsphere://unknown"), is("resource"));
+    }
+    
     @Test
     void assertGetToolDescriptors() {
         Collection<MCPToolDescriptor> actualDescriptors = MCPDescriptorCatalogIndex.getToolDescriptors();
@@ -87,12 +97,6 @@ class MCPDescriptorCatalogIndexTest {
         assertThat(actual.getTemplateResource(), is("META-INF/shardingsphere-mcp/prompts/inspect-metadata.md"));
     }
     
-    @Test
-    void assertFindToolRuntimeDescriptor() {
-        assertTrue(MCPDescriptorCatalogIndex.findToolRuntimeDescriptor("database_gateway_apply_workflow")
-                .filter(optional -> optional.getWorkflowRole().isEmpty() && optional.getSideEffectScope().contains("rule-metadata")).isPresent());
-    }
-    
     @Test
     void assertFindToolRuntimeDescriptorWithoutRuntimeMetadata() {
         assertFalse(MCPDescriptorCatalogIndex.findToolRuntimeDescriptor("database_gateway_validate_workflow").isPresent());
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 69b482cf57e..a2ca8d8db96 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
@@ -125,7 +125,7 @@ class MCPDescriptorCatalogValidatorTest {
         String toolName = "database_gateway_test_plan_rule";
         assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, createPlanningToolAnnotations(),
                 createWorkflowPlanOutputSchema(), createPlanningToolMetaWithoutWorkflowKind())),
-                List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
+                List.of(new MCPToolRuntimeDescriptor(toolName, "plan"))),
                 "Tool `database_gateway_test_plan_rule` metadata must declare `org.apache.shardingsphere/workflow-kind`.");
     }
     
@@ -136,8 +136,8 @@ class MCPDescriptorCatalogValidatorTest {
         MCPToolDescriptor secondTool = createToolDescriptor("database_gateway_test_plan_rule_again", createPlanningToolAnnotations(),
                 createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"));
         assertValidationError(createToolRuntimeCatalog(List.of(), List.of(firstTool, secondTool), List.of(
-                new MCPToolRuntimeDescriptor(firstTool.getName(), "plan", List.of()),
-                new MCPToolRuntimeDescriptor(secondTool.getName(), "plan", List.of()))),
+                new MCPToolRuntimeDescriptor(firstTool.getName(), "plan"),
+                new MCPToolRuntimeDescriptor(secondTool.getName(), "plan"))),
                 "Planning workflow kind `test.rule` is used by both `database_gateway_test_plan_rule` and `database_gateway_test_plan_rule_again`.");
     }
     
@@ -145,24 +145,16 @@ class MCPDescriptorCatalogValidatorTest {
     void assertValidateRejectsUnsupportedWorkflowRole() {
         MCPToolDescriptor descriptor = createToolDescriptor(createReadOnlyToolAnnotations());
         assertValidationError(createToolRuntimeCatalog(List.of(), List.of(descriptor),
-                List.of(new MCPToolRuntimeDescriptor(descriptor.getName(), "execute", List.of()))),
+                List.of(new MCPToolRuntimeDescriptor(descriptor.getName(), "execute"))),
                 "Tool `database_gateway_test_tool` runtime workflowRole `execute` is unsupported.");
     }
     
-    @Test
-    void assertValidateRejectsUnsupportedSideEffectScope() {
-        MCPToolDescriptor descriptor = createToolDescriptor(createReadOnlyToolAnnotations());
-        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(descriptor),
-                List.of(new MCPToolRuntimeDescriptor(descriptor.getName(), "", List.of("database")))),
-                "Tool `database_gateway_test_tool` runtime sideEffectScope `database` is unsupported.");
-    }
-    
     @Test
     void assertValidateRejectsPlanningToolReadOnlyHint() {
         String toolName = "database_gateway_test_plan_rule";
         assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, MCPToolAnnotations.builder()
                 .title("Test Tool").readOnlyHint(true).destructiveHint(false).idempotentHint(false).openWorldHint(true).build(),
-                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
+                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan"))),
                 "Planning tool `database_gateway_test_plan_rule` annotations.readOnlyHint must be false.");
     }
     
@@ -171,7 +163,7 @@ class MCPDescriptorCatalogValidatorTest {
         String toolName = "database_gateway_test_plan_rule";
         assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, MCPToolAnnotations.builder()
                 .title("Test Tool").readOnlyHint(false).destructiveHint(true).idempotentHint(false).openWorldHint(true).build(),
-                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
+                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan"))),
                 "Planning tool `database_gateway_test_plan_rule` annotations.destructiveHint must be false.");
     }
     
@@ -180,40 +172,34 @@ class MCPDescriptorCatalogValidatorTest {
         String toolName = "database_gateway_test_plan_rule";
         assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, MCPToolAnnotations.builder()
                 .title("Test Tool").readOnlyHint(false).destructiveHint(false).idempotentHint(true).openWorldHint(true).build(),
-                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
+                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan"))),
                 "Planning tool `database_gateway_test_plan_rule` annotations.idempotentHint must be false.");
     }
     
     @Test
     void assertValidateRejectsDestructiveToolWithoutExecutionMode() {
-        assertDestructiveToolValidationError(false, List.of(), false, List.of("rule-metadata"),
+        assertDestructiveToolValidationError(false, List.of(), false,
                 "Destructive tool `database_gateway_test_tool` must declare execution_mode.");
     }
     
     @Test
     void assertValidateRejectsDestructiveToolWithOptionalExecutionMode() {
-        assertDestructiveToolValidationError(true, List.of("preview"), false, List.of("rule-metadata"),
+        assertDestructiveToolValidationError(true, List.of("preview"), false,
                 "Destructive tool `database_gateway_test_tool` execution_mode must be required.");
     }
     
     @Test
     void assertValidateRejectsDestructiveToolWithoutPreview() {
-        assertDestructiveToolValidationError(true, List.of("review-then-execute"), true, List.of("rule-metadata"),
+        assertDestructiveToolValidationError(true, List.of("review-then-execute"), true,
                 "Destructive tool `database_gateway_test_tool` execution_mode must allow preview.");
     }
     
     @Test
     void assertValidateRejectsDestructiveToolWithAutoExecute() {
-        assertDestructiveToolValidationError(true, List.of("preview", "auto-execute"), true, List.of("rule-metadata"),
+        assertDestructiveToolValidationError(true, List.of("preview", "auto-execute"), true,
                 "Destructive tool `database_gateway_test_tool` execution_mode must not expose auto-execute.");
     }
     
-    @Test
-    void assertValidateRejectsDestructiveToolWithoutSideEffectScope() {
-        assertDestructiveToolValidationError(true, List.of("preview"), true, List.of(),
-                "Destructive tool `database_gateway_test_tool` must declare sideEffectScope in internal runtime.");
-    }
-    
     @ParameterizedTest(name = "{0}")
     @ValueSource(strings = {"preview", "auto-execute"})
     void assertValidateRejectsNonDestructiveExecutionMode(final String executionMode) {
@@ -334,10 +320,9 @@ class MCPDescriptorCatalogValidatorTest {
     }
     
     private void assertDestructiveToolValidationError(final boolean executionModePresent, final List<String> executionModes, final boolean executionModeRequired,
-                                                      final List<String> sideEffectScope, final String expectedMessage) {
+                                                      final String expectedMessage) {
         MCPToolDescriptor descriptor = createExecutionModeTool(true, executionModePresent, executionModes, executionModeRequired);
-        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(descriptor),
-                List.of(new MCPToolRuntimeDescriptor(descriptor.getName(), "", sideEffectScope))), expectedMessage);
+        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(descriptor), List.of()), expectedMessage);
     }
     
     private MCPToolDescriptor createExecutionModeTool(final boolean destructive, final boolean executionModePresent, final List<String> executionModes,
diff --git a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilderTest.java b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilderTest.java
index 372a37fc6cc..4c5ca14404f 100644
--- a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilderTest.java
+++ b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPResourceNavigationPayloadBuilderTest.java
@@ -64,11 +64,8 @@ class MCPResourceNavigationPayloadBuilderTest {
     
     private static Stream<Arguments> resourceKinds() {
         return Stream.of(
-                Arguments.of("rule", "shardingsphere://databases/{database}/rules", "rule"),
-                Arguments.of("algorithm", "shardingsphere://databases/{database}/algorithms", "algorithm"),
-                Arguments.of("column", "shardingsphere://databases/{database}/columns", "column"),
-                Arguments.of("index", "shardingsphere://databases/{database}/indexes", "index"),
-                Arguments.of("resource", "shardingsphere://databases/{database}", "resource"));
+                Arguments.of("workflow", "shardingsphere://workflows/{database}", "workflow-plan"),
+                Arguments.of("resource", "shardingsphere://unknown/{database}", "resource"));
     }
     
     private MCPResourceDescriptor createDescriptor(final String uriTemplate) {
diff --git a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPShardingSphereDescriptorCatalogTest.java b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPShardingSphereDescriptorCatalogTest.java
index d10d1b0f26b..d29eea723c2 100644
--- a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPShardingSphereDescriptorCatalogTest.java
+++ b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/descriptor/MCPShardingSphereDescriptorCatalogTest.java
@@ -60,7 +60,7 @@ class MCPShardingSphereDescriptorCatalogTest {
     
     @Test
     void assertGetToolRuntimeDescriptors() {
-        Collection<MCPToolRuntimeDescriptor> toolRuntimeDescriptors = List.of(new MCPToolRuntimeDescriptor("database_gateway_test_tool", "plan", List.of("metadata")));
+        Collection<MCPToolRuntimeDescriptor> toolRuntimeDescriptors = List.of(new MCPToolRuntimeDescriptor("database_gateway_test_tool", "plan"));
         MCPShardingSphereDescriptorCatalog actual = new MCPShardingSphereDescriptorCatalog(List.of(), List.of(), List.of(), List.of(), toolRuntimeDescriptors);
         assertThat(actual.getToolRuntimeDescriptors(), is(toolRuntimeDescriptors));
     }
diff --git a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContractTest.java b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContractTest.java
index 2107a16ea63..1f329e4993e 100644
--- a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContractTest.java
+++ b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPModelFacingPayloadContractTest.java
@@ -20,7 +20,7 @@ package org.apache.shardingsphere.mcp.support.protocol;
 import org.junit.jupiter.api.Test;
 
 import java.util.Collection;
-import java.util.Set;
+import java.util.List;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -41,13 +41,13 @@ class MCPModelFacingPayloadContractTest {
     
     @Test
     void assertGetNextActionRequiredFields() {
-        assertThat(MCPModelFacingPayloadContract.getNextActionRequiredFields("tool_call"), is(Set.of("order", "type", "title", "tool_name", "arguments")));
+        assertThat(MCPModelFacingPayloadContract.getNextActionRequiredFields("tool_call"), is(List.of("order", "type", "title", "tool_name", "arguments")));
     }
     
     @Test
     void assertGetNextActionAllowedFields() {
         assertThat(MCPModelFacingPayloadContract.getNextActionAllowedFields("completion"),
-                is(Set.of("order", "type", "title", "ref", "argument", "context", "missing_context_arguments", "resume_ref", "resume_arguments", "reason", "depends_on")));
+                is(List.of("order", "type", "title", "ref", "argument", "context", "missing_context_arguments", "resume_ref", "resume_arguments", "reason", "depends_on")));
     }
     
     @Test
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/DockerImageHttpRuntime.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/DockerImageHttpRuntime.java
index 26982f99b4a..2acd33151dd 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/DockerImageHttpRuntime.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/DockerImageHttpRuntime.java
@@ -26,13 +26,14 @@ import org.apache.shardingsphere.test.e2e.mcp.support.transport.client.MCPIntera
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.net.ServerSocket;
 import java.net.URI;
 import java.net.http.HttpClient;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.OptionalInt;
+import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
 
@@ -48,6 +49,8 @@ public final class DockerImageHttpRuntime implements AutoCloseable {
     
     private static final long STARTUP_POLL_INTERVAL_MILLIS = 250L;
     
+    private static final long PORT_QUERY_TIMEOUT_SECONDS = 5L;
+    
     private final String imageName;
     
     private final Path configFile;
@@ -60,6 +63,8 @@ public final class DockerImageHttpRuntime implements AutoCloseable {
     
     private int httpPort;
     
+    private String containerName;
+    
     /**
      * Open an HTTP interaction client after the Docker image becomes ready.
      *
@@ -92,6 +97,8 @@ public final class DockerImageHttpRuntime implements AutoCloseable {
         } finally {
             process = null;
             outputCollector = null;
+            httpPort = 0;
+            containerName = null;
             outputMessages.clear();
         }
     }
@@ -100,14 +107,19 @@ public final class DockerImageHttpRuntime implements AutoCloseable {
         if (null != process) {
             return;
         }
-        httpPort = allocatePort();
-        process = new ProcessBuilder(createDockerCommand(httpPort)).redirectErrorStream(true).start();
-        outputCollector = startOutputCollector(process);
+        containerName = "shardingsphere-mcp-e2e-" + UUID.randomUUID();
+        try {
+            process = new ProcessBuilder(createDockerCommand(imageName, configFile, containerName)).redirectErrorStream(true).start();
+            outputCollector = startOutputCollector(process);
+        } catch (final IOException ex) {
+            containerName = null;
+            throw ex;
+        }
     }
     
-    private List<String> createDockerCommand(final int httpPort) {
-        List<String> result = new LinkedList<>(List.of("docker", "run", "--rm", "--add-host=host.docker.internal:host-gateway", "-p",
-                "127.0.0.1:" + httpPort + ":18088", "-e", "SHARDINGSPHERE_MCP_TRANSPORT=http"));
+    static List<String> createDockerCommand(final String imageName, final Path configFile, final String containerName) {
+        List<String> result = new LinkedList<>(List.of("docker", "run", "--rm", "--name", containerName,
+                "--add-host=host.docker.internal:host-gateway", "-p", "127.0.0.1::18088", "-e", "SHARDINGSPHERE_MCP_TRANSPORT=http"));
         if (null != configFile) {
             result.addAll(List.of("-v", configFile.toAbsolutePath().normalize() + ":" + CONTAINER_CONFIG_FILE + ":ro", "-e",
                     "SHARDINGSPHERE_MCP_CONFIG=" + CONTAINER_CONFIG_FILE));
@@ -116,12 +128,6 @@ public final class DockerImageHttpRuntime implements AutoCloseable {
         return result;
     }
     
-    private int allocatePort() throws IOException {
-        try (ServerSocket serverSocket = new ServerSocket(0)) {
-            return serverSocket.getLocalPort();
-        }
-    }
-    
     private Thread startOutputCollector(final Process process) {
         Thread result = new Thread(() -> collectOutput(process), "mcp-container-http-e2e");
         result.setDaemon(true);
@@ -143,6 +149,16 @@ public final class DockerImageHttpRuntime implements AutoCloseable {
         if (!process.isAlive()) {
             return ReadinessResult.failed(null);
         }
+        if (0 == httpPort) {
+            try {
+                httpPort = queryPublishedPort();
+            } catch (final IOException ex) {
+                return ReadinessResult.retry(new IllegalStateException("Docker MCP HTTP published port is not available yet.", ex));
+            }
+            if (0 == httpPort) {
+                return ReadinessResult.retry(new IllegalStateException("Docker MCP HTTP published port has not been assigned yet."));
+            }
+        }
         MCPHttpInteractionClient result = new MCPHttpInteractionClient(URI.create("http://127.0.0.1:" + httpPort + "/mcp"), HttpClient.newHttpClient());
         try {
             result.open();
@@ -153,6 +169,37 @@ public final class DockerImageHttpRuntime implements AutoCloseable {
         }
     }
     
+    private int queryPublishedPort() throws IOException, InterruptedException {
+        Process portQuery = new ProcessBuilder("docker", "port", containerName, "18088/tcp").redirectErrorStream(true).start();
+        try {
+            if (!portQuery.waitFor(PORT_QUERY_TIMEOUT_SECONDS, TimeUnit.SECONDS) || 0 != portQuery.exitValue()) {
+                return 0;
+            }
+            return parsePublishedPort(new String(portQuery.getInputStream().readAllBytes(), StandardCharsets.UTF_8)).orElse(0);
+        } finally {
+            if (portQuery.isAlive()) {
+                portQuery.destroyForcibly();
+            }
+        }
+    }
+    
+    static OptionalInt parsePublishedPort(final String output) {
+        for (String each : output.lines().toList()) {
+            int separatorIndex = each.lastIndexOf(':');
+            if (separatorIndex < 0 || separatorIndex == each.length() - 1) {
+                continue;
+            }
+            try {
+                int result = Integer.parseInt(each.substring(separatorIndex + 1).trim());
+                if (result > 0 && result <= 65535) {
+                    return OptionalInt.of(result);
+                }
+            } catch (final NumberFormatException ignored) {
+            }
+        }
+        return OptionalInt.empty();
+    }
+    
     private IllegalStateException createStartupFailure(final Exception cause, final int ignoredAttemptCount, final long ignoredElapsedMillis) {
         return new IllegalStateException("Docker MCP HTTP distribution failed to become ready. output: " + ProcessOutputDiagnostics.format(outputMessages), cause);
     }
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/DockerImageHttpRuntimeTest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/DockerImageHttpRuntimeTest.java
new file mode 100644
index 00000000000..829e6ece466
--- /dev/null
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/DockerImageHttpRuntimeTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.test.e2e.mcp.support.distribution;
+
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Path;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class DockerImageHttpRuntimeTest {
+    
+    @Test
+    void assertCreateDockerCommandUsesRuntimeAssignedPort() {
+        List<String> actual = DockerImageHttpRuntime.createDockerCommand("shardingsphere-mcp:test", Path.of("mcp.yaml"), "mcp-e2e-test");
+        assertThat(actual.get(actual.indexOf("-p") + 1), is("127.0.0.1::18088"));
+        assertThat(actual, hasItems("--name", "mcp-e2e-test", "SHARDINGSPHERE_MCP_TRANSPORT=http", "shardingsphere-mcp:test"));
+    }
+    
+    @Test
+    void assertParsePublishedIPv4Port() {
+        assertThat(DockerImageHttpRuntime.parsePublishedPort("127.0.0.1:49152\n").orElseThrow(), is(49152));
+    }
+    
+    @Test
+    void assertParsePublishedIPv6Port() {
+        assertThat(DockerImageHttpRuntime.parsePublishedPort("[::1]:49153\n").orElseThrow(), is(49153));
+    }
+    
+    @Test
+    void assertParsePublishedPortRejectsMissingPort() {
+        assertTrue(DockerImageHttpRuntime.parsePublishedPort("published port is unavailable").isEmpty());
+    }
+    
+    @Test
+    void assertParsePublishedPortRejectsOutOfRangePort() {
+        assertTrue(DockerImageHttpRuntime.parsePublishedPort("127.0.0.1:70000").isEmpty());
+    }
+}
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionHttpRuntime.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionHttpRuntime.java
index db02c0aee4a..2f1e4c9bc15 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionHttpRuntime.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionHttpRuntime.java
@@ -24,7 +24,10 @@ import org.apache.shardingsphere.test.e2e.mcp.support.transport.client.MCPHttpIn
 import org.apache.shardingsphere.test.e2e.mcp.support.transport.client.MCPInteractionClient;
 
 import java.io.IOException;
+import java.net.URI;
 import java.net.http.HttpClient;
+import java.util.Collection;
+import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -36,12 +39,11 @@ public final class PackagedDistributionHttpRuntime implements AutoCloseable {
     
     private static final long STARTUP_POLL_INTERVAL_MILLIS = 250L;
     
-    private final PreparedPackagedDistribution distribution;
+    private static final String ENDPOINT_MARKER = "endpoint=";
     
     private final PackagedDistributionProcessSupport processSupport;
     
     public PackagedDistributionHttpRuntime(final PreparedPackagedDistribution distribution) {
-        this.distribution = distribution;
         processSupport = new PackagedDistributionProcessSupport(distribution, "mcp-packaged-http-e2e");
     }
     
@@ -67,7 +69,11 @@ public final class PackagedDistributionHttpRuntime implements AutoCloseable {
         if (!processSupport.isAlive()) {
             return ReadinessResult.failed(null);
         }
-        MCPHttpInteractionClient result = new MCPHttpInteractionClient(distribution.getEndpointUri(), HttpClient.newHttpClient());
+        Optional<URI> endpointUri = findEndpointUri(processSupport.getOutputMessages());
+        if (endpointUri.isEmpty()) {
+            return ReadinessResult.retry(new IllegalStateException("Packaged MCP HTTP endpoint has not been reported yet."));
+        }
+        MCPHttpInteractionClient result = new MCPHttpInteractionClient(endpointUri.get(), HttpClient.newHttpClient());
         try {
             result.open();
             return ReadinessResult.ready(result);
@@ -89,4 +95,24 @@ public final class PackagedDistributionHttpRuntime implements AutoCloseable {
             Thread.currentThread().interrupt();
         }
     }
+    
+    static Optional<URI> findEndpointUri(final Collection<String> outputMessages) {
+        for (String each : outputMessages) {
+            int startIndex = each.indexOf(ENDPOINT_MARKER);
+            if (startIndex < 0) {
+                continue;
+            }
+            startIndex += ENDPOINT_MARKER.length();
+            int endIndex = each.indexOf(',', startIndex);
+            String candidate = each.substring(startIndex, endIndex < 0 ? each.length() : endIndex).trim();
+            try {
+                URI result = URI.create(candidate);
+                if ("http".equalsIgnoreCase(result.getScheme()) && null != result.getHost() && result.getPort() > 0) {
+                    return Optional.of(result);
+                }
+            } catch (final IllegalArgumentException ignored) {
+            }
+        }
+        return Optional.empty();
+    }
 }
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionHttpRuntimeTest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionHttpRuntimeTest.java
new file mode 100644
index 00000000000..8d68afd9ea8
--- /dev/null
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionHttpRuntimeTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.test.e2e.mcp.support.distribution;
+
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+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 PackagedDistributionHttpRuntimeTest {
+    
+    @Test
+    void assertFindEndpointUri() {
+        URI actual = PackagedDistributionHttpRuntime.findEndpointUri(List.of(
+                "ShardingSphere MCP Server started, transport=http, endpoint=http://127.0.0.1:49152/mcp, logs=logs.")).orElseThrow();
+        assertThat(actual, is(URI.create("http://127.0.0.1:49152/mcp")));
+    }
+    
+    @Test
+    void assertFindEndpointUriIgnoresInvalidMessages() {
+        assertTrue(PackagedDistributionHttpRuntime.findEndpointUri(List.of(
+                "ShardingSphere MCP Server started, transport=http, endpoint=http://127.0.0.1:0/mcp.",
+                "Unrelated startup output.")).isEmpty());
+    }
+}
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java
index 10bca0f9aee..33aec6f703d 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupport.java
@@ -30,8 +30,6 @@ import org.apache.shardingsphere.test.e2e.env.runtime.EnvironmentPropertiesLoade
 import org.apache.shardingsphere.test.e2e.mcp.support.runtime.RuntimeTransport;
 
 import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.URI;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -104,9 +102,8 @@ public final class PackagedDistributionTestSupport {
     
     private static PreparedPackagedDistribution createPreparedDistribution(final Path workingHome, final RuntimeTransport transport,
                                                                            final Map<String, RuntimeDatabaseConfiguration> runtimeDatabases) throws IOException {
-        int httpPort = resolveHttpPort(transport);
-        Path configFile = rewriteConfiguration(workingHome, transport, httpPort, runtimeDatabases);
-        return new PreparedPackagedDistribution(workingHome, configFile, transport, httpPort);
+        Path configFile = rewriteConfiguration(workingHome, transport, runtimeDatabases);
+        return new PreparedPackagedDistribution(workingHome, configFile, transport);
     }
     
     /**
@@ -261,21 +258,11 @@ public final class PackagedDistributionTestSupport {
         }
     }
     
-    private static int allocatePort() throws IOException {
-        try (ServerSocket serverSocket = new ServerSocket(0)) {
-            return serverSocket.getLocalPort();
-        }
-    }
-    
-    private static int resolveHttpPort(final RuntimeTransport transport) throws IOException {
-        return RuntimeTransport.HTTP == transport ? allocatePort() : -1;
-    }
-    
-    private static Path rewriteConfiguration(final Path workingHome, final RuntimeTransport transport, final int httpPort,
+    private static Path rewriteConfiguration(final Path workingHome, final RuntimeTransport transport,
                                              final Map<String, RuntimeDatabaseConfiguration> runtimeDatabases) throws IOException {
         Path result = resolveConfigFile(workingHome, transport);
         MCPLaunchConfiguration sourceConfig = MCPConfigurationLoader.load(result.toString());
-        return writeConfiguration(result, createRuntimeConfiguration(sourceConfig, transport, httpPort, runtimeDatabases));
+        return writeConfiguration(result, createRuntimeConfiguration(sourceConfig, transport, runtimeDatabases));
     }
     
     private static Path resolveConfigFile(final Path workingHome, final RuntimeTransport transport) {
@@ -283,9 +270,9 @@ public final class PackagedDistributionTestSupport {
     }
     
     private static MCPLaunchConfiguration createRuntimeConfiguration(final MCPLaunchConfiguration sourceConfig, final RuntimeTransport transport,
-                                                                     final int httpPort, final Map<String, RuntimeDatabaseConfiguration> runtimeDatabases) {
+                                                                     final Map<String, RuntimeDatabaseConfiguration> runtimeDatabases) {
         HttpTransportConfiguration actualHttpTransport = new HttpTransportConfiguration(sourceConfig.getHttpTransport().getBindHost(),
-                RuntimeTransport.HTTP == transport ? httpPort : sourceConfig.getHttpTransport().getPort(), sourceConfig.getHttpTransport().getEndpointPath());
+                RuntimeTransport.HTTP == transport ? 0 : sourceConfig.getHttpTransport().getPort(), sourceConfig.getHttpTransport().getEndpointPath());
         return new MCPLaunchConfiguration(resolveTransportType(transport), actualHttpTransport, runtimeDatabases.isEmpty() ? sourceConfig.getDatabases() : runtimeDatabases);
     }
     
@@ -293,14 +280,10 @@ public final class PackagedDistributionTestSupport {
         return RuntimeTransport.HTTP == transport ? MCPTransportType.HTTP : MCPTransportType.STDIO;
     }
     
-    public record PreparedPackagedDistribution(Path home, Path configFile, RuntimeTransport transport, int httpPort) {
+    public record PreparedPackagedDistribution(Path home, Path configFile, RuntimeTransport transport) {
 
         public Path getStartScript() {
             return PackagedDistributionProcessSupport.resolveStartScript(home);
         }
-
-        public URI getEndpointUri() {
-            return URI.create(String.format("http://127.0.0.1:%d/mcp", httpPort));
-        }
     }
 }
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java
index a533b1bc0a2..5cc12dc23ba 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/distribution/PackagedDistributionTestSupportTest.java
@@ -17,7 +17,6 @@
 
 package org.apache.shardingsphere.test.e2e.mcp.support.distribution;
 
-import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.is;
 
 import org.apache.shardingsphere.mcp.bootstrap.config.MCPLaunchConfiguration;
@@ -152,10 +151,8 @@ class PackagedDistributionTestSupportTest {
             MCPLaunchConfiguration actualConfig = MCPConfigurationLoader.load(actual.configFile().toString());
             assertThat(actualConfig.getTransportType(), is(expectedTransportType));
             if (RuntimeTransport.HTTP == transport) {
-                assertThat(actual.httpPort(), greaterThan(0));
-                assertThat(actualConfig.getHttpTransport().getPort(), is(actual.httpPort()));
+                assertThat(actualConfig.getHttpTransport().getPort(), is(0));
             } else {
-                assertThat(actual.httpPort(), is(-1));
                 assertThat(actualConfig.getHttpTransport().getPort(), is(18088));
             }
         } finally {
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeDockerSupportTest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeDockerSupportTest.java
new file mode 100644
index 00000000000..42b0ca497b5
--- /dev/null
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeDockerSupportTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.test.e2e.mcp.support.runtime;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Properties;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class MySQLRuntimeDockerSupportTest {
+    
+    @Test
+    void assertCreateDockerRequiredMessageWithReadinessDiagnostic() {
+        assertThat(MySQLRuntimeDockerSupport.createDockerRequiredMessage("Docker is required.", "daemon unavailable"),
+                is("Docker is required. Docker readiness diagnostic: daemon unavailable"));
+    }
+    
+    @Test
+    void assertCreateDockerRequiredMessageWithoutReadinessDiagnostic() {
+        assertThat(MySQLRuntimeDockerSupport.createDockerRequiredMessage("Docker is required.", ""), is("Docker is required."));
+    }
+    
+    @Test
+    void assertGetMySQLImage() {
+        Properties props = new Properties();
+        props.setProperty("mcp.e2e.mysql.image", "mysql:8.4.0");
+        assertThat(MySQLRuntimeDockerSupport.getMySQLImage(props), is("mysql:8.4.0"));
+    }
+    
+    @Test
+    void assertGetMySQLImageWithMissingProperty() {
+        IllegalStateException actualException = assertThrows(IllegalStateException.class, () -> MySQLRuntimeDockerSupport.getMySQLImage(new Properties()));
+        assertThat(actualException.getMessage(), is("MCP E2E MySQL image property `mcp.e2e.mysql.image` is required."));
+    }
+}
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java
index 1cb3c2e1f7f..2a110f03e4d 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupport.java
@@ -36,8 +36,6 @@ import java.time.Duration;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
-import java.util.Properties;
 
 /**
  * E2E-local MySQL-backed runtime test support.
@@ -83,10 +81,6 @@ public final class MySQLRuntimeTestSupport {
                 .withStartupTimeout(Duration.ofMinutes(2));
     }
     
-    static String getMySQLImage(final Properties props) {
-        return MySQLRuntimeDockerSupport.getMySQLImage(props);
-    }
-    
     /**
      * Check whether Docker is available for Testcontainers-backed tests.
      *
@@ -96,15 +90,6 @@ public final class MySQLRuntimeTestSupport {
         return MySQLRuntimeDockerSupport.isDockerAvailable();
     }
     
-    /**
-     * Get Docker readiness diagnostic when Testcontainers cannot use Docker.
-     *
-     * @return Docker unavailable reason
-     */
-    public static Optional<String> getDockerUnavailableReason() {
-        return MySQLRuntimeDockerSupport.getDockerUnavailableReason();
-    }
-    
     /**
      * Create Docker-required message with bounded readiness diagnostics.
      *
@@ -115,10 +100,6 @@ public final class MySQLRuntimeTestSupport {
         return MySQLRuntimeDockerSupport.createDockerRequiredMessage(scenarioMessage);
     }
     
-    static String createDockerRequiredMessage(final String scenarioMessage, final String unavailableReason) {
-        return MySQLRuntimeDockerSupport.createDockerRequiredMessage(scenarioMessage, unavailableReason);
-    }
-    
     /**
      * Create runtime databases for the MySQL-backed runtime.
      *
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupportTest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupportTest.java
index ceac136ac3b..aee9f40e929 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupportTest.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/support/runtime/MySQLRuntimeTestSupportTest.java
@@ -21,8 +21,6 @@ import org.junit.jupiter.api.Test;
 import org.mockito.MockedStatic;
 import org.testcontainers.containers.GenericContainer;
 
-import java.util.Properties;
-
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.sameInstance;
@@ -34,30 +32,6 @@ import static org.mockito.Mockito.mockStatic;
 
 class MySQLRuntimeTestSupportTest {
     
-    @Test
-    void assertCreateDockerRequiredMessageWithReadinessDiagnostic() {
-        assertThat(MySQLRuntimeTestSupport.createDockerRequiredMessage("Docker is required.", "daemon unavailable"),
-                is("Docker is required. Docker readiness diagnostic: daemon unavailable"));
-    }
-    
-    @Test
-    void assertCreateDockerRequiredMessageWithoutReadinessDiagnostic() {
-        assertThat(MySQLRuntimeTestSupport.createDockerRequiredMessage("Docker is required.", ""), is("Docker is required."));
-    }
-    
-    @Test
-    void assertGetMySQLImage() {
-        Properties props = new Properties();
-        props.setProperty("mcp.e2e.mysql.image", "mysql:8.4.0");
-        assertThat(MySQLRuntimeTestSupport.getMySQLImage(props), is("mysql:8.4.0"));
-    }
-    
-    @Test
-    void assertGetMySQLImageWithMissingProperty() {
-        IllegalStateException actualException = assertThrows(IllegalStateException.class, () -> MySQLRuntimeTestSupport.getMySQLImage(new Properties()));
-        assertThat(actualException.getMessage(), is("MCP E2E MySQL image property `mcp.e2e.mysql.image` is required."));
-    }
-    
     @Test
     void assertCreateLLMRuntimeFixturePreservesInitializationFailure() {
         GenericContainer<?> container = mock(GenericContainer.class);