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/10 05:48:24 UTC

(shardingsphere) branch master updated: Refine MCP workflow contracts and test boundaries (#39067)

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 cc62c18a6ca Refine MCP workflow contracts and test boundaries (#39067)
cc62c18a6ca is described below

commit cc62c18a6ca63f3c8f770fb26130612fc23e8c80
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Fri Jul 10 13:48:19 2026 +0800

    Refine MCP workflow contracts and test boundaries (#39067)
    
    * Refine MCP workflow contracts and test boundaries
    
    - centralize approved_steps usage and next-action ordering
    - validate planning tool annotations in descriptor catalog checks
    - keep collaborator replacement in tests instead of production constructors
    - include LLM usability artifact directories in failure summaries
    
    * Refine MCP workflow contracts and test boundaries
    
    - centralize approved_steps usage and next-action ordering
    - validate planning tool annotations in descriptor catalog checks
    - keep collaborator replacement in tests instead of production constructors
    - include LLM usability artifact directories in failure summaries
---
 .codex/skills/review-pr/SKILL.md                   |   2 +
 AGENTS.md                                          |   2 +
 .../tool/MCPCallToolResultFactoryTest.java         |  63 ++------
 .../transport/server/MCPSyncServerFactoryTest.java |  28 ++--
 .../server/http/StreamableHttpMCPServerTest.java   |   7 +-
 .../server/http/StreamableHttpMCPServletTest.java  |  54 ++++---
 .../error/MCPWorkflowRecoveryPayloadFactory.java   |   2 +-
 .../core/tool/handler/MCPToolArgumentContract.java |   7 +-
 .../metadata/SearchMetadataPayloadBuilder.java     |  13 +-
 .../workflow/WorkflowExecutionToolHandler.java     |   2 +-
 .../workflow/WorkflowApplyResponseBuilder.java     |   4 +-
 .../core/workflow/WorkflowExecutionService.java    |   6 +-
 .../workflow/WorkflowExecutionToolHandlerTest.java |   7 +-
 .../handler/EncryptAlgorithmsHandlerTest.java      |  21 +--
 .../resource/handler/EncryptRuleHandlerTest.java   |  23 +--
 .../resource/handler/EncryptRulesHandlerTest.java  |  21 +--
 .../tool/handler/EncryptToolHandlerTest.java       | 176 ++++++++++-----------
 .../EncryptWorkflowPlanningServiceTest.java        |  50 +++---
 .../EncryptWorkflowValidationServiceTest.java      |  34 ++--
 .../handler/MaskAlgorithmsHandlerTest.java         |  21 +--
 .../mask/resource/handler/MaskRuleHandlerTest.java |  23 +--
 .../resource/handler/MaskRulesHandlerTest.java     |  21 +--
 .../mask/tool/handler/MaskToolHandlerTest.java     | 135 ++++++++--------
 .../service/MaskWorkflowValidationServiceTest.java |  30 ++--
 ...riteSplittingWorkflowValidationServiceTest.java |  34 ++--
 .../ShadowWorkflowValidationServiceTest.java       |  16 +-
 .../ShardingWorkflowValidationServiceTest.java     |  22 +--
 .../MCPToolDescriptorCatalogValidator.java         |  12 ++
 .../mcp/support/protocol/MCPNextActionUtils.java   |  20 ++-
 .../support/workflow/model/WorkflowFieldNames.java |   2 +
 .../MCPDescriptorCatalogValidatorTest.java         |  34 +++-
 .../support/protocol/MCPNextActionUtilsTest.java   |   9 ++
 .../suite/usability/LLMUsabilitySuiteRunner.java   |  29 ++--
 .../usability/LLMUsabilitySuiteRunnerTest.java     |  12 ++
 34 files changed, 507 insertions(+), 435 deletions(-)

diff --git a/.codex/skills/review-pr/SKILL.md b/.codex/skills/review-pr/SKILL.md
index 2ac16853a6e..9791bf1f4a6 100644
--- a/.codex/skills/review-pr/SKILL.md
+++ b/.codex/skills/review-pr/SKILL.md
@@ -189,6 +189,8 @@ Choose the feedback mode from the `Verdict Matrix` before writing the GitHub-fac
 - Do not run `git diff --check`, editor whitespace lint, or other generic whitespace diagnostics as routine review verification.
   Use them only when repository workflows explicitly require them, the user asks for whitespace review, the review target is formatting rules, or whitespace has direct semantic impact.
 - Do not report Spotless-stable whitespace, including formatter-preserved blank-line indentation, as a blocker.
+- Before publishing any formatting, whitespace, import-only, or formatter-only finding, record the repository-declared gate command and result that proves it.
+  If the only failing evidence is a generic lint while Spotless and Checkstyle pass or preserve the changed whitespace, withdraw the finding.
 - Include import-only, whitespace-only, and formatter-only files in `Reviewed Scope` when GitHub lists them.
 - Do not report them as blockers or rollback requests unless they hide behavior, fail style gates, touch broad unrelated areas, or violate explicit scope rules.
 
diff --git a/AGENTS.md b/AGENTS.md
index ba50974ece2..df71826f786 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -53,6 +53,8 @@ This guide is written **for AI coding agents only**. Follow it literally; improv
       Production changes must have an independent production reason, such as fixing behavior, clarifying a real contract, reducing production duplication,
       or exposing a construction path that production code legitimately supports.
       Prefer test-local fixtures, mocks, existing public constructors, factories, builders, SPI loaders, or production APIs when construction is incidental to the behavior under test.
+      Do not split a simple production class into a public no-argument constructor plus a package-private collaborator constructor merely to replace an internally created collaborator in tests.
+      For simple handlers, adapters, or payload builders with one or two locally created collaborators, keep the production construction shape and adapt or remove the test unless there is an independent production boundary reason.
       If a change is only needed by tests, do not make the production change.
     - New internal abstractions must reduce cognitive complexity instead of merely wrapping branches in more types.
       For simple internal two-path flows, avoid marker interfaces, multi-type result hierarchies, or extra DTO-style helpers.
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPCallToolResultFactoryTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPCallToolResultFactoryTest.java
index ae0b1b029eb..1e6eb8bb5c5 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPCallToolResultFactoryTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPCallToolResultFactoryTest.java
@@ -25,27 +25,18 @@ import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
 import io.modelcontextprotocol.spec.McpSchema.ResourceLink;
 import io.modelcontextprotocol.spec.McpSchema.TextContent;
 import org.apache.shardingsphere.mcp.api.protocol.response.MCPResponse;
-import org.apache.shardingsphere.mcp.api.tool.MCPToolCall;
 import org.apache.shardingsphere.mcp.api.tool.descriptor.MCPToolDescriptor;
 import org.apache.shardingsphere.mcp.core.protocol.response.MCPErrorResponse;
 import org.apache.shardingsphere.mcp.core.tool.handler.MCPToolDefinition;
 import org.apache.shardingsphere.mcp.core.tool.handler.ToolDefinitionRegistry;
-import org.apache.shardingsphere.mcp.core.workflow.InMemoryWorkflowSessionContext;
 import org.apache.shardingsphere.mcp.feature.encrypt.EncryptFeatureDefinition;
-import org.apache.shardingsphere.mcp.feature.encrypt.tool.handler.PlanEncryptRuleToolHandler;
 import org.apache.shardingsphere.mcp.feature.encrypt.tool.model.EncryptWorkflowRequest;
-import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptWorkflowPlanningService;
+import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptAlgorithmPropertyTemplateService;
 import org.apache.shardingsphere.mcp.feature.mask.MaskFeatureDefinition;
-import org.apache.shardingsphere.mcp.feature.mask.tool.handler.PlanMaskRuleToolHandler;
-import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskWorkflowPlanningService;
-import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
-import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
-import org.apache.shardingsphere.mcp.support.database.spi.MCPMetadataQueryFacade;
+import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskAlgorithmPropertyTemplateService;
 import org.apache.shardingsphere.mcp.support.descriptor.MCPShardingSphereMetadataKeys;
 import org.apache.shardingsphere.mcp.support.protocol.MCPResourceHintUtils;
 import org.apache.shardingsphere.mcp.support.protocol.response.MCPMapResponse;
-import org.apache.shardingsphere.mcp.support.workflow.MCPWorkflowHandlerContext;
-import org.apache.shardingsphere.mcp.support.workflow.WorkflowSessionContext;
 import org.apache.shardingsphere.mcp.support.workflow.model.AlgorithmPropertyRequirement;
 import org.apache.shardingsphere.mcp.support.workflow.model.ClarifiedIntent;
 import org.apache.shardingsphere.mcp.support.workflow.model.InteractionPlan;
@@ -54,11 +45,10 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnaps
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowKind;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowLifecycle;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowRequest;
+import org.apache.shardingsphere.mcp.support.workflow.service.WorkflowPlanPayloadBuilder;
 import org.junit.jupiter.api.Test;
 import org.mockito.MockedStatic;
-import org.mockito.internal.configuration.plugins.Plugins;
 
-import java.lang.reflect.Field;
 import java.util.List;
 import java.util.Map;
 
@@ -67,10 +57,7 @@ import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.isA;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.when;
 
 class MCPCallToolResultFactoryTest extends AbstractMCPToolSpecificationFactoryTest {
     
@@ -109,14 +96,14 @@ class MCPCallToolResultFactoryTest extends AbstractMCPToolSpecificationFactoryTe
     }
     
     @Test
-    void assertCreateWithMaskWorkflowPlanSchema() throws ReflectiveOperationException {
+    void assertCreateWithMaskWorkflowPlanSchema() {
         CallToolResult actual = createRealDescriptorCallToolResult(MaskFeatureDefinition.PLAN_TOOL_NAME, createMaskPlanResponse());
         assertFalse(actual.isError(), () -> String.valueOf(actual.structuredContent()));
         assertThat(getStructuredContent(actual).get("status"), is("planned"));
     }
     
     @Test
-    void assertCreateWithEncryptWorkflowPlanSchema() throws ReflectiveOperationException {
+    void assertCreateWithEncryptWorkflowPlanSchema() {
         CallToolResult actual = createRealDescriptorCallToolResult(EncryptFeatureDefinition.PLAN_TOOL_NAME, createEncryptPlanResponse());
         assertFalse(actual.isError(), () -> String.valueOf(actual.structuredContent()));
         assertThat(getStructuredContent(actual).get("status"), is("planned"));
@@ -221,12 +208,12 @@ class MCPCallToolResultFactoryTest extends AbstractMCPToolSpecificationFactoryTe
         return new MCPCallToolResultFactory().create(descriptor, response);
     }
     
-    private MCPResponse createMaskPlanResponse() throws ReflectiveOperationException {
-        PlanMaskRuleToolHandler handler = new PlanMaskRuleToolHandler();
-        MaskWorkflowPlanningService planningService = mock(MaskWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createMaskSnapshot());
-        setField(handler, "planningService", planningService);
-        return handler.handle(createWorkflowContext(), new MCPToolCall("session-id", Map.of("database", "logic_db", "table", "orders", "column", "phone")));
+    private MCPResponse createMaskPlanResponse() {
+        WorkflowContextSnapshot snapshot = createMaskSnapshot();
+        Map<String, Object> payload = WorkflowPlanPayloadBuilder.buildRuleDistSQLOnly(snapshot, snapshot.getRequest());
+        payload.put("masked_property_preview", Map.of("primary",
+                new MaskAlgorithmPropertyTemplateService().maskProperties(snapshot.getPropertyRequirements(), snapshot.getRequest().getPrimaryAlgorithmProperties())));
+        return new MCPMapResponse(payload);
     }
     
     private WorkflowContextSnapshot createMaskSnapshot() {
@@ -240,12 +227,12 @@ class MCPCallToolResultFactoryTest extends AbstractMCPToolSpecificationFactoryTe
         return result;
     }
     
-    private MCPResponse createEncryptPlanResponse() throws ReflectiveOperationException {
-        PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
-        EncryptWorkflowPlanningService planningService = mock(EncryptWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createEncryptSnapshot());
-        setField(handler, "planningService", planningService);
-        return handler.handle(createWorkflowContext(), new MCPToolCall("session-id", Map.of("database", "logic_db", "table", "orders", "column", "phone")));
+    private MCPResponse createEncryptPlanResponse() {
+        WorkflowContextSnapshot snapshot = createEncryptSnapshot();
+        Map<String, Object> payload = WorkflowPlanPayloadBuilder.buildRuleDistSQLOnly(snapshot, snapshot.getRequest());
+        payload.put("masked_property_preview", Map.of("primary",
+                new EncryptAlgorithmPropertyTemplateService().maskProperties(snapshot.getPropertyRequirements(), snapshot.getRequest().getPrimaryAlgorithmProperties())));
+        return new MCPMapResponse(payload);
     }
     
     private WorkflowContextSnapshot createEncryptSnapshot() {
@@ -287,22 +274,6 @@ class MCPCallToolResultFactoryTest extends AbstractMCPToolSpecificationFactoryTe
         return result;
     }
     
-    private MCPWorkflowHandlerContext createWorkflowContext() {
-        MCPWorkflowHandlerContext result = mock(MCPWorkflowHandlerContext.class);
-        MCPDatabaseHandlerContext databaseContext = mock(MCPDatabaseHandlerContext.class);
-        WorkflowSessionContext workflowSessionContext = new InMemoryWorkflowSessionContext();
-        when(result.getDatabaseContext()).thenReturn(databaseContext);
-        when(result.getWorkflowSessionContext()).thenReturn(workflowSessionContext);
-        when(databaseContext.getMetadataQueryFacade()).thenReturn(mock(MCPMetadataQueryFacade.class));
-        when(databaseContext.getQueryFacade()).thenReturn(mock(MCPFeatureQueryFacade.class));
-        return result;
-    }
-    
-    private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
-        Field field = target.getClass().getDeclaredField(fieldName);
-        Plugins.getMemberAccessor().set(field, target, value);
-    }
-    
     @SuppressWarnings("unchecked")
     private List<Map<String, Object>> getOutputSchemaExamples(final MCPToolDescriptor toolDescriptor) {
         return toolDescriptor.getOutputSchema().containsKey("examples") ? (List<Map<String, Object>>) toolDescriptor.getOutputSchema().get("examples") : List.of();
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/MCPSyncServerFactoryTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/MCPSyncServerFactoryTest.java
index cd4c38c11cb..8d972137784 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/MCPSyncServerFactoryTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/MCPSyncServerFactoryTest.java
@@ -17,7 +17,6 @@
 
 package org.apache.shardingsphere.mcp.bootstrap.transport.server;
 
-import io.modelcontextprotocol.json.McpJsonMapper;
 import io.modelcontextprotocol.server.McpServerFeatures.SyncCompletionSpecification;
 import io.modelcontextprotocol.server.McpServerFeatures.SyncPromptSpecification;
 import io.modelcontextprotocol.server.McpServerFeatures.SyncResourceSpecification;
@@ -58,7 +57,7 @@ import static org.mockito.Mockito.when;
 class MCPSyncServerFactoryTest {
     
     @Test
-    void assertCreateWithTransportProvider() throws ReflectiveOperationException {
+    void assertCreateWithTransportProvider() {
         TestServerTransportProvider transportProvider = new TestServerTransportProvider();
         McpSyncServer actual = createFactory().create(transportProvider);
         assertNotNull(transportProvider.sessionFactory);
@@ -73,7 +72,7 @@ class MCPSyncServerFactoryTest {
     }
     
     @Test
-    void assertCreateWithStreamableTransportProvider() throws ReflectiveOperationException {
+    void assertCreateWithStreamableTransportProvider() {
         TestStreamableTransportProvider transportProvider = new TestStreamableTransportProvider();
         McpSyncServer actual = createFactory().create(transportProvider);
         assertNotNull(transportProvider.sessionFactory);
@@ -84,7 +83,7 @@ class MCPSyncServerFactoryTest {
     }
     
     @Test
-    void assertCreateExposesOfficialDiscoveryDescriptors() throws ReflectiveOperationException {
+    void assertCreateExposesOfficialDiscoveryDescriptors() {
         TestServerTransportProvider transportProvider = new TestServerTransportProvider();
         McpSyncServer actual = createFactory().create(transportProvider);
         assertToolDiscoveryDescriptor(actual.listTools().get(0));
@@ -95,7 +94,7 @@ class MCPSyncServerFactoryTest {
     }
     
     @Test
-    void assertCreateAdvertisesImplementedCapabilitiesAndSdkLoggingOnly() throws ReflectiveOperationException {
+    void assertCreateAdvertisesImplementedCapabilitiesAndSdkLoggingOnly() {
         TestServerTransportProvider transportProvider = new TestServerTransportProvider();
         McpSyncServer actual = createFactory().create(transportProvider);
         McpSchema.ServerCapabilities actualCapabilities = actual.getServerCapabilities();
@@ -112,7 +111,7 @@ class MCPSyncServerFactoryTest {
         actual.closeGracefully();
     }
     
-    private MCPSyncServerFactory createFactory() throws ReflectiveOperationException {
+    private MCPSyncServerFactory createFactory() {
         MCPToolSpecificationFactory toolSpecificationFactory = mock(MCPToolSpecificationFactory.class);
         MCPResourceSpecificationFactory resourceSpecificationFactory = mock(MCPResourceSpecificationFactory.class);
         MCPPromptSpecificationFactory promptSpecificationFactory = mock(MCPPromptSpecificationFactory.class);
@@ -131,15 +130,18 @@ class MCPSyncServerFactoryTest {
                 (exchange, request) -> new McpSchema.GetPromptResult("Inspect metadata", List.of()))));
         when(completionSpecificationFactory.createCompletionSpecifications()).thenReturn(List.of(new SyncCompletionSpecification(new McpSchema.PromptReference("inspect_metadata"),
                 (exchange, request) -> new McpSchema.CompleteResult(new McpSchema.CompleteResult.CompleteCompletion(List.of(), 0, false)))));
-        McpJsonMapper jsonMapper = MCPTransportJsonMapperFactory.create();
         MCPRuntimeContext runtimeContext = mock(MCPRuntimeContext.class);
         when(runtimeContext.getSessionManager()).thenReturn(mock(MCPSessionManager.class));
-        MCPSyncServerFactory result = new MCPSyncServerFactory(runtimeContext, jsonMapper);
-        setField(result, "toolSpecificationFactory", toolSpecificationFactory);
-        setField(result, "resourceSpecificationFactory", resourceSpecificationFactory);
-        setField(result, "promptSpecificationFactory", promptSpecificationFactory);
-        setField(result, "completionSpecificationFactory", completionSpecificationFactory);
-        return result;
+        MCPSyncServerFactory result = new MCPSyncServerFactory(runtimeContext, MCPTransportJsonMapperFactory.create());
+        try {
+            setField(result, "toolSpecificationFactory", toolSpecificationFactory);
+            setField(result, "resourceSpecificationFactory", resourceSpecificationFactory);
+            setField(result, "promptSpecificationFactory", promptSpecificationFactory);
+            setField(result, "completionSpecificationFactory", completionSpecificationFactory);
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private McpSchema.CallToolResult createFixtureToolResult() {
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServerTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServerTest.java
index cbd65835b42..e80e9e6c6cc 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServerTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServerTest.java
@@ -33,6 +33,7 @@ import org.junit.jupiter.api.Test;
 import org.mockito.InOrder;
 import org.mockito.MockedConstruction;
 import org.mockito.internal.configuration.plugins.Plugins;
+import reactor.core.publisher.Mono;
 
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -148,9 +149,11 @@ class StreamableHttpMCPServerTest {
     
     private StreamableHttpMCPServlet createTransportServlet() {
         MCPSessionManager sessionManager = new MCPSessionManager(Collections.emptyMap());
+        HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
+        when(delegate.closeGracefully()).thenReturn(Mono.empty());
+        StreamableHttpMCPServlet result = new StreamableHttpMCPServlet(sessionManager, MCPTransportJsonMapperFactory.create(), createConfig(0));
         try {
-            StreamableHttpMCPServlet result = new StreamableHttpMCPServlet(sessionManager, MCPTransportJsonMapperFactory.create(), createConfig(0));
-            setField(result, "delegate", mock(HttpServletStreamableServerTransportProvider.class));
+            setField(result, "delegate", delegate);
             setField(result, "sessionExecutionCoordinator", new MCPSessionExecutionCoordinator(sessionManager));
             return result;
         } catch (final ReflectiveOperationException ex) {
diff --git a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServletTest.java b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServletTest.java
index 22fa133af8b..ea125d8c26a 100644
--- a/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServletTest.java
+++ b/mcp/bootstrap/src/test/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServletTest.java
@@ -37,8 +37,8 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.mockito.internal.configuration.plugins.Plugins;
 import org.mockito.ArgumentCaptor;
+import org.mockito.internal.configuration.plugins.Plugins;
 import reactor.core.publisher.Mono;
 
 import java.io.IOException;
@@ -63,14 +63,14 @@ class StreamableHttpMCPServletTest {
     private static final String ACCEPT = "application/json, text/event-stream";
     
     @Test
-    void assertProtocolVersions() throws ReflectiveOperationException {
+    void assertProtocolVersions() {
         StreamableHttpMCPServlet actual = createServlet(mock(HttpServletStreamableServerTransportProvider.class), mock(MCPSessionManager.class),
                 mock(MCPSessionExecutionCoordinator.class));
         assertThat(actual.protocolVersions(), is(MCPTransportConstants.SUPPORTED_PROTOCOL_VERSIONS));
     }
     
     @Test
-    void assertSetSessionFactoryWithSupportedProtocolVersion() throws ReflectiveOperationException {
+    void assertSetSessionFactoryWithSupportedProtocolVersion() {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         MCPSessionManager sessionManager = mock(MCPSessionManager.class);
         McpStreamableServerSession.Factory sessionFactory = mock(McpStreamableServerSession.Factory.class);
@@ -93,7 +93,7 @@ class StreamableHttpMCPServletTest {
     
     @ParameterizedTest(name = "{0}")
     @MethodSource("unsupportedProtocolVersions")
-    void assertSetSessionFactoryWithNegotiatedProtocolVersion(final String name, final String requestedProtocolVersion) throws ReflectiveOperationException {
+    void assertSetSessionFactoryWithNegotiatedProtocolVersion(final String name, final String requestedProtocolVersion) {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         MCPSessionManager sessionManager = mock(MCPSessionManager.class);
         McpStreamableServerSession.Factory sessionFactory = mock(McpStreamableServerSession.Factory.class);
@@ -128,7 +128,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertNotifyClients() throws ReflectiveOperationException {
+    void assertNotifyClients() {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         Mono<Void> expected = Mono.empty();
         when(delegate.notifyClients("notifications/tools/list_changed", Map.of("status", "ok"))).thenReturn(expected);
@@ -137,7 +137,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertNotifyClient() throws ReflectiveOperationException {
+    void assertNotifyClient() {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         Mono<Void> expected = Mono.empty();
         when(delegate.notifyClient("session-id", "notifications/resources/list_changed", Map.of("status", "ok"))).thenReturn(expected);
@@ -147,7 +147,7 @@ class StreamableHttpMCPServletTest {
     
     @ParameterizedTest(name = "{0}")
     @MethodSource("requestMethods")
-    void assertServiceSetUtf8Encoding(final String name, final String requestMethod) throws ServletException, IOException, ReflectiveOperationException {
+    void assertServiceSetUtf8Encoding(final String name, final String requestMethod) throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn(requestMethod);
@@ -168,7 +168,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServiceGetWithoutAcceptHeaderAndUtf8Encoding() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServiceGetWithoutAcceptHeaderAndUtf8Encoding() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("GET");
@@ -184,7 +184,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertRejectUnsupportedEventStreamGet() throws ServletException, IOException, ReflectiveOperationException {
+    void assertRejectUnsupportedEventStreamGet() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("GET");
@@ -200,7 +200,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServicePostWithSessionHeaderSet() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServicePostWithSessionHeaderSet() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("POST");
@@ -219,7 +219,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServicePostBindSessionIdentity() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServicePostBindSessionIdentity() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         MCPSessionManager sessionManager = mock(MCPSessionManager.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
@@ -243,7 +243,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServicePostWithJsonContentType() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServicePostWithJsonContentType() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("POST");
@@ -257,7 +257,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServicePostRejectUnsupportedContentType() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServicePostRejectUnsupportedContentType() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("POST");
@@ -270,7 +270,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServicePostWithNegotiatedProtocolHeader() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServicePostWithNegotiatedProtocolHeader() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("POST");
@@ -287,7 +287,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServicePostWithSessionHeaderAdded() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServicePostWithSessionHeaderAdded() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("POST");
@@ -306,7 +306,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServicePostWithoutSessionHeader() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServicePostWithoutSessionHeader() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
         when(request.getMethod()).thenReturn("POST");
@@ -328,7 +328,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServiceDeleteCloseSessionWhenStatusOk() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServiceDeleteCloseSessionWhenStatusOk() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         MCPSessionExecutionCoordinator sessionExecutionCoordinator = mock(MCPSessionExecutionCoordinator.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
@@ -345,7 +345,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertServiceDeleteSkipCloseSessionWhenStatusNotOk() throws ServletException, IOException, ReflectiveOperationException {
+    void assertServiceDeleteSkipCloseSessionWhenStatusNotOk() throws ServletException, IOException {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         MCPSessionExecutionCoordinator sessionExecutionCoordinator = mock(MCPSessionExecutionCoordinator.class);
         HttpServletRequest request = mock(HttpServletRequest.class);
@@ -362,7 +362,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertCloseGracefully() throws ReflectiveOperationException {
+    void assertCloseGracefully() {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         MCPSessionExecutionCoordinator sessionExecutionCoordinator = mock(MCPSessionExecutionCoordinator.class);
         when(delegate.closeGracefully()).thenReturn(Mono.empty());
@@ -374,7 +374,7 @@ class StreamableHttpMCPServletTest {
     }
     
     @Test
-    void assertDestroy() throws ReflectiveOperationException {
+    void assertDestroy() {
         HttpServletStreamableServerTransportProvider delegate = mock(HttpServletStreamableServerTransportProvider.class);
         MCPSessionExecutionCoordinator sessionExecutionCoordinator = mock(MCPSessionExecutionCoordinator.class);
         when(delegate.closeGracefully()).thenReturn(Mono.empty());
@@ -385,17 +385,21 @@ class StreamableHttpMCPServletTest {
     }
     
     private StreamableHttpMCPServlet createServlet(final HttpServletStreamableServerTransportProvider delegate, final MCPSessionManager sessionManager,
-                                                   final MCPSessionExecutionCoordinator sessionExecutionCoordinator) throws ReflectiveOperationException {
+                                                   final MCPSessionExecutionCoordinator sessionExecutionCoordinator) {
         return createServlet(delegate, sessionManager, sessionExecutionCoordinator,
                 new HttpTransportConfiguration("127.0.0.1", 18088, "/mcp"));
     }
     
     private StreamableHttpMCPServlet createServlet(final HttpServletStreamableServerTransportProvider delegate, final MCPSessionManager sessionManager,
-                                                   final MCPSessionExecutionCoordinator sessionExecutionCoordinator, final HttpTransportConfiguration config) throws ReflectiveOperationException {
+                                                   final MCPSessionExecutionCoordinator sessionExecutionCoordinator, final HttpTransportConfiguration config) {
         StreamableHttpMCPServlet result = new StreamableHttpMCPServlet(sessionManager, MCPTransportJsonMapperFactory.create(), config);
-        setField(result, "delegate", delegate);
-        setField(result, "sessionExecutionCoordinator", sessionExecutionCoordinator);
-        return result;
+        try {
+            setField(result, "delegate", delegate);
+            setField(result, "sessionExecutionCoordinator", sessionExecutionCoordinator);
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/protocol/error/MCPWorkflowRecoveryPayloadFactory.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/protocol/error/MCPWorkflowRecoveryPayloadFactory.java
index 3fdd8a02c9c..2fac38a4472 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/protocol/error/MCPWorkflowRecoveryPayloadFactory.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/protocol/error/MCPWorkflowRecoveryPayloadFactory.java
@@ -50,7 +50,7 @@ final class MCPWorkflowRecoveryPayloadFactory {
                 "invalid_enum_value", "Retry database_gateway_apply_workflow with execution_mode=preview, review the returned preview_artifacts, "
                         + "then pass explicit approved_steps copied from visible preview_artifacts.approval_step values.");
         Map<String, Object> suggestedArguments = MCPRecoveryPayloadSupport.getSuggestedArguments(cause.getSuggestedArguments(), Map.of(WorkflowFieldNames.EXECUTION_MODE, "preview"));
-        result.put(MCPPayloadFieldNames.FIELD, "approved_steps");
+        result.put(MCPPayloadFieldNames.FIELD, WorkflowFieldNames.APPROVED_STEPS);
         result.put(MCPPayloadFieldNames.ALLOWED_VALUES, cause.getAllowedValues());
         result.put("suggested_arguments", suggestedArguments);
         result.put(MCPPayloadFieldNames.NEXT_ACTIONS, List.of(MCPNextActionUtils.callTool(
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/MCPToolArgumentContract.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/MCPToolArgumentContract.java
index 2f15c959d03..e7ca4b448f7 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/MCPToolArgumentContract.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/MCPToolArgumentContract.java
@@ -28,6 +28,7 @@ import org.apache.shardingsphere.mcp.core.protocol.exception.MCPInvalidToolArgum
 import org.apache.shardingsphere.mcp.core.protocol.exception.MCPMissingToolArgumentException;
 import org.apache.shardingsphere.mcp.core.protocol.exception.MCPToolArgumentContractViolationException;
 import org.apache.shardingsphere.mcp.support.protocol.MCPPayloadFieldNames;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowFieldNames;
 
 import java.math.BigInteger;
 import java.util.Collection;
@@ -40,8 +41,6 @@ import java.util.Objects;
 @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
 final class MCPToolArgumentContract {
     
-    private static final String APPROVED_STEPS = "approved_steps";
-    
     private static final String TYPE = "type";
     
     private static final String PROPERTIES = "properties";
@@ -234,7 +233,7 @@ final class MCPToolArgumentContract {
         if (MCPPayloadFieldNames.EXECUTION_MODE.equals(argumentName)) {
             return new MCPInvalidExecutionModeException(toolName, allowedValues, createExecutionModeSuggestedArguments(arguments, allowedValues));
         }
-        if (argumentName.startsWith(APPROVED_STEPS + "[")) {
+        if (argumentName.startsWith(WorkflowFieldNames.APPROVED_STEPS + "[")) {
             return new MCPInvalidApprovedStepsException(allowedValues, createApprovedStepsSuggestedArguments(arguments));
         }
         return createContractViolationException(arguments, argumentName, "invalid_enum_value", "", allowedValues);
@@ -272,7 +271,7 @@ final class MCPToolArgumentContract {
     
     private Map<String, Object> createApprovedStepsSuggestedArguments(final Map<String, Object> arguments) {
         Map<String, Object> result = new LinkedHashMap<>(arguments);
-        result.remove(APPROVED_STEPS);
+        result.remove(WorkflowFieldNames.APPROVED_STEPS);
         String suggestedExecutionMode = findSafestExecutionMode(getEnumValues(findProperty(inputSchema, MCPPayloadFieldNames.EXECUTION_MODE)));
         if (!suggestedExecutionMode.isEmpty()) {
             result.put(MCPPayloadFieldNames.EXECUTION_MODE, suggestedExecutionMode);
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataPayloadBuilder.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataPayloadBuilder.java
index 44e27bbb61a..14660e78f0c 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataPayloadBuilder.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/metadata/SearchMetadataPayloadBuilder.java
@@ -104,24 +104,13 @@ public final class SearchMetadataPayloadBuilder {
             result.add(MCPNextActionUtils.askUser("Multiple metadata hits share the same name. Ask the user to choose database, schema, or object type before using a specific resource.",
                     List.of("database", "schema", "object_types")));
         }
-        return addOrder(result);
+        return MCPNextActionUtils.ordered(result);
     }
     
     private static boolean isBroadSearchGuarded(final MetadataSearchResult searchResult) {
         return Boolean.TRUE.equals(searchResult.getSearchContext().get("broad_search_guarded"));
     }
     
-    private static List<Map<String, Object>> addOrder(final List<Map<String, Object>> actions) {
-        List<Map<String, Object>> result = new LinkedList<>();
-        int order = 1;
-        for (Map<String, Object> each : actions) {
-            Map<String, Object> action = new LinkedHashMap<>(each);
-            action.put("order", order++);
-            result.add(action);
-        }
-        return result;
-    }
-    
     private static List<String> findDuplicatedNames(final List<MetadataSearchHit> items, final String query) {
         Set<String> observedNames = new LinkedHashSet<>();
         Set<String> duplicatedNames = new LinkedHashSet<>();
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandler.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandler.java
index 8db961fb8c5..831ab6ac8e4 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandler.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandler.java
@@ -78,7 +78,7 @@ public final class WorkflowExecutionToolHandler implements MCPToolHandler<MCPWor
         WorkflowRuntimeDefinition workflowRuntimeDefinition = workflowRuntimeDefinitionRegistry.getRequired(workflowKind);
         return new MCPMapResponse(executionService.apply(workflowContext.getWorkflowSessionContext(), databaseContext.getMetadataQueryFacade(), databaseContext.getQueryFacade(),
                 databaseContext.getExecutionFacade(), workflowRuntimeDefinition.getApplySynchronizationHandler(), workflowRuntimeDefinition.getApplyArtifactValidator(), toolCall.getSessionId(),
-                snapshot, toolArguments.getStringCollectionArgument("approved_steps"), executionMode));
+                snapshot, toolArguments.getStringCollectionArgument(WorkflowFieldNames.APPROVED_STEPS), executionMode));
     }
     
     private WorkflowKind getRequiredWorkflowKind(final WorkflowContextSnapshot snapshot) {
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java
index 9132b122e1a..f7b35662fad 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowApplyResponseBuilder.java
@@ -159,7 +159,7 @@ public final class WorkflowApplyResponseBuilder {
         boolean manualOnly = EXECUTION_MODE_MANUAL_ONLY.equals(applyExecutionMode);
         result.put("manual_only", manualOnly);
         if (!manualOnly && !previewArtifacts.isEmpty()) {
-            result.put("approval_field", "approved_steps");
+            result.put("approval_field", WorkflowFieldNames.APPROVED_STEPS);
             result.put("approval_values", previewArtifacts.stream().map(each -> (String) each.get("approval_step")).distinct().toList());
         }
         return result;
@@ -191,7 +191,7 @@ public final class WorkflowApplyResponseBuilder {
                     createPreviewNextActionReason(applyExecutionMode), createExecutionArguments(snapshot, applyExecutionMode)));
         }
         return MCPNextActionUtils.ordered(
-                MCPNextActionUtils.askUser(createPreviewNextActionReason(applyExecutionMode), List.of("approved_steps")),
+                MCPNextActionUtils.askUser(createPreviewNextActionReason(applyExecutionMode), List.of(WorkflowFieldNames.APPROVED_STEPS)),
                 MCPNextActionUtils.dependsOn(MCPNextActionUtils.callTool(WorkflowToolDescriptors.APPLY_TOOL_NAME,
                         "Apply reviewed workflow artifacts after merging approved_steps from action 1 into the arguments.",
                         createExecutionArguments(snapshot, applyExecutionMode)), 1));
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 d4dc4740eaa..e5fb2a4bc77 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
@@ -62,7 +62,7 @@ public final class WorkflowExecutionService {
     
     private static final List<String> EXECUTION_MODES = List.of(EXECUTION_MODE_PREVIEW, EXECUTION_MODE_REVIEW_THEN_EXECUTE, EXECUTION_MODE_MANUAL_ONLY);
     
-    private static final List<String> APPROVED_STEPS = List.of(
+    private static final List<String> ALLOWED_APPROVAL_STEPS = List.of(
             WorkflowArtifactPayloadUtils.STEP_DDL, WorkflowArtifactPayloadUtils.STEP_INDEX_DDL, WorkflowArtifactPayloadUtils.STEP_RULE_DISTSQL);
     
     /**
@@ -142,8 +142,8 @@ public final class WorkflowExecutionService {
             return;
         }
         for (String each : approvedSteps) {
-            if (!APPROVED_STEPS.contains(each)) {
-                throw new MCPInvalidApprovedStepsException(APPROVED_STEPS, createPreviewSuggestedArguments(snapshot));
+            if (!ALLOWED_APPROVAL_STEPS.contains(each)) {
+                throw new MCPInvalidApprovedStepsException(ALLOWED_APPROVAL_STEPS, createPreviewSuggestedArguments(snapshot));
             }
         }
     }
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandlerTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandlerTest.java
index 38948309aa2..abbaa852de1 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandlerTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/workflow/WorkflowExecutionToolHandlerTest.java
@@ -28,6 +28,7 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnaps
 import org.apache.shardingsphere.mcp.support.workflow.spi.MCPWorkflowApplyArtifactValidator;
 import org.apache.shardingsphere.mcp.support.workflow.spi.MCPWorkflowApplySynchronizationHandler;
 import org.apache.shardingsphere.mcp.support.workflow.spi.MCPWorkflowValidationHandler;
+import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowFieldNames;
 import org.junit.jupiter.api.Test;
 import org.mockito.internal.configuration.plugins.Plugins;
 
@@ -64,7 +65,7 @@ class WorkflowExecutionToolHandlerTest {
         WorkflowExecutionToolHandler handler = createExecutionToolHandler(executionService, new WorkflowRuntimeDefinitionRegistry(List.of(
                 WorkflowHandlerTestFixture.createDefinition("encrypt.rule", mock(MCPWorkflowValidationHandler.class), workflowApplySynchronizationHandler, workflowApplyArtifactValidator))));
         MCPResponse actual = handler.handle(fixture.workflowContext(), new MCPToolCall("session-1",
-                Map.of("plan_id", "plan-1", "approved_steps", List.of("ddl"), "execution_mode", "manual-only")));
+                Map.of(WorkflowFieldNames.PLAN_ID, "plan-1", WorkflowFieldNames.APPROVED_STEPS, List.of("ddl"), WorkflowFieldNames.EXECUTION_MODE, "manual-only")));
         verify(executionService).apply(eq(fixture.workflowSessionContext()), eq(fixture.metadataQueryFacade()), eq(fixture.queryFacade()), eq(fixture.executionFacade()),
                 eq(workflowApplySynchronizationHandler), eq(workflowApplyArtifactValidator), eq("session-1"), eq(snapshot), eq(List.of("ddl")), eq("manual-only"));
         assertThat(actual.toPayload().get("status"), is("completed"));
@@ -76,7 +77,7 @@ class WorkflowExecutionToolHandlerTest {
         WorkflowHandlerTestFixture.Context fixture = WorkflowHandlerTestFixture.createContext(snapshot);
         WorkflowExecutionToolHandler handler = new WorkflowExecutionToolHandler(new WorkflowRuntimeDefinitionRegistry(List.of(WorkflowHandlerTestFixture.createDefinition("encrypt.rule"))));
         MCPInvalidRequestException actual = assertThrows(MCPInvalidRequestException.class,
-                () -> handler.handle(fixture.workflowContext(), new MCPToolCall("session-1", Map.of("plan_id", "plan-1", "execution_mode", "manual-only"))));
+                () -> handler.handle(fixture.workflowContext(), new MCPToolCall("session-1", Map.of(WorkflowFieldNames.PLAN_ID, "plan-1", WorkflowFieldNames.EXECUTION_MODE, "manual-only"))));
         assertThat(actual.getMessage(), is("Workflow kind is required for plan_id `plan-1`."));
     }
     
@@ -86,7 +87,7 @@ class WorkflowExecutionToolHandlerTest {
         WorkflowHandlerTestFixture.Context fixture = WorkflowHandlerTestFixture.createContext(snapshot);
         WorkflowExecutionToolHandler handler = new WorkflowExecutionToolHandler(new WorkflowRuntimeDefinitionRegistry(List.of(WorkflowHandlerTestFixture.createDefinition("encrypt.rule"))));
         MCPInvalidRequestException actual = assertThrows(MCPInvalidRequestException.class,
-                () -> handler.handle(fixture.workflowContext(), new MCPToolCall("session-1", Map.of("plan_id", "plan-1"))));
+                () -> handler.handle(fixture.workflowContext(), new MCPToolCall("session-1", Map.of(WorkflowFieldNames.PLAN_ID, "plan-1"))));
         assertThat(actual.getMessage(), is("database_gateway_apply_workflow execution_mode is required."));
     }
     
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 612d7730102..7a063fda91c 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
@@ -24,7 +24,7 @@ import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptRuleIns
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.junit.jupiter.api.Test;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
 import java.util.Collection;
 import java.util.List;
@@ -33,6 +33,7 @@ import java.util.Map;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -49,17 +50,17 @@ class EncryptAlgorithmsHandlerTest {
     }
     
     @Test
-    void assertHandle() throws ReflectiveOperationException {
-        EncryptAlgorithmsHandler handler = new EncryptAlgorithmsHandler();
-        EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
+    void assertHandle() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         MCPDatabaseHandlerContext databaseContext = mock(MCPDatabaseHandlerContext.class);
         when(databaseContext.getQueryFacade()).thenReturn(queryFacade);
-        when(ruleInspectionService.queryEncryptAlgorithms(queryFacade)).thenReturn(List.of(Map.of("type", "AES")));
-        Plugins.getMemberAccessor().set(EncryptAlgorithmsHandler.class.getDeclaredField("ruleInspectionService"), handler, ruleInspectionService);
-        MCPResponse actual = handler.handle(databaseContext, new MCPUriVariables(Map.of()));
-        verify(ruleInspectionService).queryEncryptAlgorithms(queryFacade);
-        assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
-        assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/encrypt/algorithms"));
+        try (
+                MockedConstruction<EncryptRuleInspectionService> mockedConstruction = mockConstruction(EncryptRuleInspectionService.class,
+                        (mock, context) -> when(mock.queryEncryptAlgorithms(queryFacade)).thenReturn(List.of(Map.of("type", "AES"))))) {
+            MCPResponse actual = new EncryptAlgorithmsHandler().handle(databaseContext, new MCPUriVariables(Map.of()));
+            verify(mockedConstruction.constructed().getFirst()).queryEncryptAlgorithms(queryFacade);
+            assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
+            assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/encrypt/algorithms"));
+        }
     }
 }
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRuleHandlerTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRuleHandlerTest.java
index d8c92b24be4..3b975fafabb 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRuleHandlerTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRuleHandlerTest.java
@@ -24,7 +24,7 @@ import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptRuleIns
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.junit.jupiter.api.Test;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
 import java.util.Collection;
 import java.util.List;
@@ -33,6 +33,7 @@ import java.util.Map;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -49,18 +50,18 @@ class EncryptRuleHandlerTest {
     }
     
     @Test
-    void assertHandle() throws ReflectiveOperationException {
-        EncryptRuleHandler handler = new EncryptRuleHandler();
-        EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
+    void assertHandle() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         MCPDatabaseHandlerContext databaseContext = mock(MCPDatabaseHandlerContext.class);
         when(databaseContext.getQueryFacade()).thenReturn(queryFacade);
-        when(ruleInspectionService.queryEncryptRules(queryFacade, "logic_db", "orders")).thenReturn(List.of(Map.of("logic_column", "phone")));
-        Plugins.getMemberAccessor().set(EncryptRuleHandler.class.getDeclaredField("ruleInspectionService"), handler, ruleInspectionService);
-        MCPResponse actual = handler.handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db", "table", "orders")));
-        verify(ruleInspectionService).queryEncryptRules(queryFacade, "logic_db", "orders");
-        assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
-        assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/encrypt/databases/logic_db/tables/orders/rules"));
-        assertThat(((Map<?, ?>) actual.toPayload().get("parent_resource")).get("uri"), is("shardingsphere://features/encrypt/databases/logic_db/rules"));
+        try (
+                MockedConstruction<EncryptRuleInspectionService> mockedConstruction = mockConstruction(EncryptRuleInspectionService.class,
+                        (mock, context) -> when(mock.queryEncryptRules(queryFacade, "logic_db", "orders")).thenReturn(List.of(Map.of("logic_column", "phone"))))) {
+            MCPResponse actual = new EncryptRuleHandler().handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db", "table", "orders")));
+            verify(mockedConstruction.constructed().getFirst()).queryEncryptRules(queryFacade, "logic_db", "orders");
+            assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
+            assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/encrypt/databases/logic_db/tables/orders/rules"));
+            assertThat(((Map<?, ?>) actual.toPayload().get("parent_resource")).get("uri"), is("shardingsphere://features/encrypt/databases/logic_db/rules"));
+        }
     }
 }
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRulesHandlerTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRulesHandlerTest.java
index 86199f66e34..aafe7656e84 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRulesHandlerTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/resource/handler/EncryptRulesHandlerTest.java
@@ -24,7 +24,7 @@ import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptRuleIns
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.junit.jupiter.api.Test;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
 import java.util.Collection;
 import java.util.List;
@@ -33,6 +33,7 @@ import java.util.Map;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -49,17 +50,17 @@ class EncryptRulesHandlerTest {
     }
     
     @Test
-    void assertHandle() throws ReflectiveOperationException {
-        EncryptRulesHandler handler = new EncryptRulesHandler();
-        EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
+    void assertHandle() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         MCPDatabaseHandlerContext databaseContext = mock(MCPDatabaseHandlerContext.class);
         when(databaseContext.getQueryFacade()).thenReturn(queryFacade);
-        when(ruleInspectionService.queryEncryptRules(queryFacade, "logic_db")).thenReturn(List.of(Map.of("logic_column", "phone")));
-        Plugins.getMemberAccessor().set(EncryptRulesHandler.class.getDeclaredField("ruleInspectionService"), handler, ruleInspectionService);
-        MCPResponse actual = handler.handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db")));
-        verify(ruleInspectionService).queryEncryptRules(queryFacade, "logic_db");
-        assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
-        assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/encrypt/databases/logic_db/rules"));
+        try (
+                MockedConstruction<EncryptRuleInspectionService> mockedConstruction = mockConstruction(EncryptRuleInspectionService.class,
+                        (mock, context) -> when(mock.queryEncryptRules(queryFacade, "logic_db")).thenReturn(List.of(Map.of("logic_column", "phone"))))) {
+            MCPResponse actual = new EncryptRulesHandler().handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db")));
+            verify(mockedConstruction.constructed().getFirst()).queryEncryptRules(queryFacade, "logic_db");
+            assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
+            assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/encrypt/databases/logic_db/rules"));
+        }
     }
 }
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/handler/EncryptToolHandlerTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/handler/EncryptToolHandlerTest.java
index 7b6beb4a407..eaf3cacf0eb 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/handler/EncryptToolHandlerTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/handler/EncryptToolHandlerTest.java
@@ -23,7 +23,6 @@ import org.apache.shardingsphere.mcp.feature.encrypt.EncryptFeatureDefinition;
 import org.apache.shardingsphere.mcp.feature.encrypt.TestWorkflowSessionContext;
 import org.apache.shardingsphere.mcp.feature.encrypt.tool.model.EncryptWorkflowRequest;
 import org.apache.shardingsphere.mcp.feature.encrypt.tool.model.EncryptWorkflowState;
-import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptAlgorithmPropertyTemplateService;
 import org.apache.shardingsphere.mcp.feature.encrypt.tool.service.EncryptWorkflowPlanningService;
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureExecutionFacade;
@@ -38,9 +37,8 @@ import org.apache.shardingsphere.mcp.support.workflow.model.RuleArtifact;
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnapshot;
 import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
-import java.lang.reflect.Field;
 import java.util.List;
 import java.util.Map;
 
@@ -51,105 +49,104 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 class EncryptToolHandlerTest {
     
     @Test
-    void assertHandlePlanEncryptRule() throws ReflectiveOperationException {
-        PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
-        EncryptWorkflowPlanningService planningService = mock(EncryptWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
-        setField(handler, "planningService", planningService);
-        setField(handler, "propertyTemplateService", new EncryptAlgorithmPropertyTemplateService());
-        WorkflowContextFixture fixture = createWorkflowContextFixture();
-        MCPResponse actual = handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
-                "database", "logic_db",
-                "table", "orders",
-                "column", "phone",
-                "algorithm_type", "AES",
-                "cipher_column_name", "phone_cipher",
-                "structured_intent_evidence", Map.of("field_semantics", "phone", "requires_decrypt", true))));
-        assertThat(actual.toPayload().get("plan_id"), is("plan-1"));
-        ArgumentCaptor<EncryptWorkflowRequest> requestCaptor = ArgumentCaptor.forClass(EncryptWorkflowRequest.class);
-        verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
-        EncryptWorkflowRequest actualRequest = requestCaptor.getValue();
-        assertThat(actualRequest.getAlgorithmType(), is("AES"));
-        assertThat(actualRequest.getFieldSemantics(), is("phone"));
-        assertThat(actualRequest.getOptions().getCipherColumnName(), is("phone_cipher"));
+    void assertHandlePlanEncryptRule() {
+        try (MockedConstruction<EncryptWorkflowPlanningService> mockedConstruction = mockConstruction(EncryptWorkflowPlanningService.class)) {
+            PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
+            EncryptWorkflowPlanningService planningService = mockedConstruction.constructed().getFirst();
+            when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
+            WorkflowContextFixture fixture = createWorkflowContextFixture();
+            MCPResponse actual = handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
+                    "database", "logic_db",
+                    "table", "orders",
+                    "column", "phone",
+                    "algorithm_type", "AES",
+                    "cipher_column_name", "phone_cipher",
+                    "structured_intent_evidence", Map.of("field_semantics", "phone", "requires_decrypt", true))));
+            assertThat(actual.toPayload().get("plan_id"), is("plan-1"));
+            ArgumentCaptor<EncryptWorkflowRequest> requestCaptor = ArgumentCaptor.forClass(EncryptWorkflowRequest.class);
+            verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
+            EncryptWorkflowRequest actualRequest = requestCaptor.getValue();
+            assertThat(actualRequest.getAlgorithmType(), is("AES"));
+            assertThat(actualRequest.getFieldSemantics(), is("phone"));
+            assertThat(actualRequest.getOptions().getCipherColumnName(), is("phone_cipher"));
+        }
     }
     
     @Test
-    void assertHandlePlanEncryptRuleWithMaskedArtifacts() throws ReflectiveOperationException {
-        PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
-        EncryptWorkflowPlanningService planningService = mock(EncryptWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createDetailedSnapshot());
-        setField(handler, "planningService", planningService);
-        setField(handler, "propertyTemplateService", new EncryptAlgorithmPropertyTemplateService());
-        MCPResponse actual = handler.handle(createWorkflowContextFixture().workflowContext, new MCPToolCall("session-1", Map.of(
-                "database", "logic_db",
-                "table", "orders",
-                "column", "phone")));
-        Map<String, Object> actualPayload = actual.toPayload();
-        assertThat(((Map<?, ?>) ((Map<?, ?>) actualPayload.get("masked_property_preview")).get("primary")).get("aes-key-value"), is("******"));
-        assertFalse(actualPayload.containsKey("derived_column_plan"));
-        assertFalse(actualPayload.containsKey("ddl_artifacts"));
-        assertFalse(actualPayload.containsKey("index_plan"));
-        assertTrue(String.valueOf(((Map<?, ?>) ((List<?>) actualPayload.get("distsql_artifacts")).getFirst()).get("sql")).contains("******"));
-        List<?> actualResourcesToRead = (List<?>) actualPayload.get("resources_to_read");
-        List<String> actualResourceUris = extractResourceUris(actualResourcesToRead);
-        assertTrue(actualResourceUris.contains("shardingsphere://features/encrypt/algorithms"));
-        assertTrue(actualResourceUris.contains("shardingsphere://features/encrypt/databases/logic_db/rules"));
-        assertTrue(actualResourceUris.contains("shardingsphere://features/encrypt/databases/logic_db/tables/orders/rules"));
-        assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/encrypt/algorithms"), is("algorithm"));
-        assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/encrypt/databases/logic_db/rules"), is("rule"));
-        assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/encrypt/databases/logic_db/tables/orders/rules"), is("rule"));
-        Map<?, ?> actualNextAction = (Map<?, ?>) ((List<?>) actualPayload.get("next_actions")).getFirst();
-        assertThat(actualNextAction.get("type"), is("tool_call"));
-        assertThat(actualNextAction.get("tool_name"), is("database_gateway_apply_workflow"));
-        assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("plan_id"), is("plan-1"));
-        assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("execution_mode"), is("preview"));
+    void assertHandlePlanEncryptRuleWithMaskedArtifacts() {
+        try (MockedConstruction<EncryptWorkflowPlanningService> mockedConstruction = mockConstruction(EncryptWorkflowPlanningService.class)) {
+            PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
+            when(mockedConstruction.constructed().getFirst().plan(any(), any(), any(), any(), any())).thenReturn(createDetailedSnapshot());
+            MCPResponse actual = handler.handle(createWorkflowContextFixture().workflowContext, new MCPToolCall("session-1", Map.of(
+                    "database", "logic_db",
+                    "table", "orders",
+                    "column", "phone")));
+            Map<String, Object> actualPayload = actual.toPayload();
+            assertThat(((Map<?, ?>) ((Map<?, ?>) actualPayload.get("masked_property_preview")).get("primary")).get("aes-key-value"), is("******"));
+            assertFalse(actualPayload.containsKey("derived_column_plan"));
+            assertFalse(actualPayload.containsKey("ddl_artifacts"));
+            assertFalse(actualPayload.containsKey("index_plan"));
+            assertTrue(String.valueOf(((Map<?, ?>) ((List<?>) actualPayload.get("distsql_artifacts")).getFirst()).get("sql")).contains("******"));
+            List<?> actualResourcesToRead = (List<?>) actualPayload.get("resources_to_read");
+            List<String> actualResourceUris = extractResourceUris(actualResourcesToRead);
+            assertTrue(actualResourceUris.contains("shardingsphere://features/encrypt/algorithms"));
+            assertTrue(actualResourceUris.contains("shardingsphere://features/encrypt/databases/logic_db/rules"));
+            assertTrue(actualResourceUris.contains("shardingsphere://features/encrypt/databases/logic_db/tables/orders/rules"));
+            assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/encrypt/algorithms"), is("algorithm"));
+            assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/encrypt/databases/logic_db/rules"), is("rule"));
+            assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/encrypt/databases/logic_db/tables/orders/rules"), is("rule"));
+            Map<?, ?> actualNextAction = (Map<?, ?>) ((List<?>) actualPayload.get("next_actions")).getFirst();
+            assertThat(actualNextAction.get("type"), is("tool_call"));
+            assertThat(actualNextAction.get("tool_name"), is("database_gateway_apply_workflow"));
+            assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("plan_id"), is("plan-1"));
+            assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("execution_mode"), is("preview"));
+        }
     }
     
     @Test
-    void assertHandlePlanEncryptRuleWithSecretReferences() throws ReflectiveOperationException {
-        PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
-        EncryptWorkflowPlanningService planningService = mock(EncryptWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
-        setField(handler, "planningService", planningService);
-        setField(handler, "propertyTemplateService", new EncryptAlgorithmPropertyTemplateService());
-        WorkflowContextFixture fixture = createWorkflowContextFixture();
-        handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
-                "database", "logic_db",
-                "primary_algorithm_properties", Map.of("aes-key-value", Map.of("secret_ref", "placeholder://secret-value-1")),
-                "assisted_query_algorithm_properties", Map.of("salt", Map.of("secret_ref", "placeholder://secret-value-2")),
-                "like_query_algorithm_properties", Map.of("token", Map.of("secret_ref", "placeholder://secret-value-3")))));
-        ArgumentCaptor<EncryptWorkflowRequest> requestCaptor = ArgumentCaptor.forClass(EncryptWorkflowRequest.class);
-        verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
-        EncryptWorkflowRequest actualRequest = requestCaptor.getValue();
-        assertThat(actualRequest.getPrimaryAlgorithmProperties().get("aes-key-value"), is("secret_reference:primary.aes-key-value"));
-        assertFalse(actualRequest.getSecretReferences("primary").get("aes-key-value").isMalformed());
-        assertThat(actualRequest.getOptions().getAssistedQueryAlgorithmProperties().get("salt"), is("secret_reference:assisted_query.salt"));
-        assertFalse(actualRequest.getSecretReferences("assisted_query").get("salt").isMalformed());
-        assertThat(actualRequest.getOptions().getLikeQueryAlgorithmProperties().get("token"), is("secret_reference:like_query.token"));
-        assertFalse(actualRequest.getSecretReferences("like_query").get("token").isMalformed());
+    void assertHandlePlanEncryptRuleWithSecretReferences() {
+        try (MockedConstruction<EncryptWorkflowPlanningService> mockedConstruction = mockConstruction(EncryptWorkflowPlanningService.class)) {
+            PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
+            EncryptWorkflowPlanningService planningService = mockedConstruction.constructed().getFirst();
+            when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
+            WorkflowContextFixture fixture = createWorkflowContextFixture();
+            handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
+                    "database", "logic_db",
+                    "primary_algorithm_properties", Map.of("aes-key-value", Map.of("secret_ref", "placeholder://secret-value-1")),
+                    "assisted_query_algorithm_properties", Map.of("salt", Map.of("secret_ref", "placeholder://secret-value-2")),
+                    "like_query_algorithm_properties", Map.of("token", Map.of("secret_ref", "placeholder://secret-value-3")))));
+            ArgumentCaptor<EncryptWorkflowRequest> requestCaptor = ArgumentCaptor.forClass(EncryptWorkflowRequest.class);
+            verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
+            EncryptWorkflowRequest actualRequest = requestCaptor.getValue();
+            assertThat(actualRequest.getPrimaryAlgorithmProperties().get("aes-key-value"), is("secret_reference:primary.aes-key-value"));
+            assertFalse(actualRequest.getSecretReferences("primary").get("aes-key-value").isMalformed());
+            assertThat(actualRequest.getOptions().getAssistedQueryAlgorithmProperties().get("salt"), is("secret_reference:assisted_query.salt"));
+            assertFalse(actualRequest.getSecretReferences("assisted_query").get("salt").isMalformed());
+            assertThat(actualRequest.getOptions().getLikeQueryAlgorithmProperties().get("token"), is("secret_reference:like_query.token"));
+            assertFalse(actualRequest.getSecretReferences("like_query").get("token").isMalformed());
+        }
     }
     
     @Test
-    void assertHandlePlanEncryptRuleMasksPropertiesBeforeRequirementsCollected() throws ReflectiveOperationException {
-        PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
-        EncryptWorkflowPlanningService planningService = mock(EncryptWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createClarifyingSnapshot());
-        setField(handler, "planningService", planningService);
-        setField(handler, "propertyTemplateService", new EncryptAlgorithmPropertyTemplateService());
-        MCPResponse actual = handler.handle(createWorkflowContextFixture().workflowContext, new MCPToolCall("session-1", Map.of(
-                "database", "logic_db",
-                "table", "orders",
-                "column", "phone")));
-        Map<String, Object> actualPayload = actual.toPayload();
-        assertThat(((Map<?, ?>) ((Map<?, ?>) actualPayload.get("masked_property_preview")).get("primary")).get("aes-key-value"), is("******"));
-        assertFalse(String.valueOf(actualPayload).contains("recovery-secret-value"));
+    void assertHandlePlanEncryptRuleMasksPropertiesBeforeRequirementsCollected() {
+        try (MockedConstruction<EncryptWorkflowPlanningService> mockedConstruction = mockConstruction(EncryptWorkflowPlanningService.class)) {
+            PlanEncryptRuleToolHandler handler = new PlanEncryptRuleToolHandler();
+            when(mockedConstruction.constructed().getFirst().plan(any(), any(), any(), any(), any())).thenReturn(createClarifyingSnapshot());
+            MCPResponse actual = handler.handle(createWorkflowContextFixture().workflowContext, new MCPToolCall("session-1", Map.of(
+                    "database", "logic_db",
+                    "table", "orders",
+                    "column", "phone")));
+            Map<String, Object> actualPayload = actual.toPayload();
+            assertThat(((Map<?, ?>) ((Map<?, ?>) actualPayload.get("masked_property_preview")).get("primary")).get("aes-key-value"), is("******"));
+            assertFalse(String.valueOf(actualPayload).contains("recovery-secret-value"));
+        }
     }
     
     private WorkflowContextSnapshot createSnapshot(final String planId, final String status) {
@@ -196,11 +193,6 @@ class EncryptToolHandlerTest {
         return result;
     }
     
-    private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
-        Field field = target.getClass().getDeclaredField(fieldName);
-        Plugins.getMemberAccessor().set(field, target, value);
-    }
-    
     private List<String> extractResourceUris(final List<?> resources) {
         return resources.stream().map(each -> (String) ((Map<?, ?>) each).get("uri")).toList();
     }
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 b7de537c6e9..16a9f2f3b58 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
@@ -59,7 +59,7 @@ import static org.mockito.Mockito.when;
 class EncryptWorkflowPlanningServiceTest {
     
     @Test
-    void assertPlanRejectsMissingPlanningContext() throws ReflectiveOperationException {
+    void assertPlanRejectsMissingPlanningContext() {
         EncryptWorkflowPlanningService service = createService(mock(EncryptRuleInspectionService.class), mock(EncryptAlgorithmRecommendationService.class),
                 mock(EncryptAlgorithmPropertyTemplateService.class), mock(EncryptRuleDistSQLPlanningService.class));
         WorkflowContextSnapshot actual = service.plan(new TestWorkflowSessionContext(), mock(MCPMetadataQueryFacade.class), mock(MCPFeatureQueryFacade.class), "session-1",
@@ -69,7 +69,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRejectsMissingTableAndColumn() throws ReflectiveOperationException {
+    void assertPlanRejectsMissingTableAndColumn() {
         EncryptWorkflowPlanningService service = createService(mock(EncryptRuleInspectionService.class), mock(EncryptAlgorithmRecommendationService.class),
                 mock(EncryptAlgorithmPropertyTemplateService.class), mock(EncryptRuleDistSQLPlanningService.class));
         EncryptWorkflowRequest request = new EncryptWorkflowRequest();
@@ -83,7 +83,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRejectsMissingLogicalColumn() throws ReflectiveOperationException {
+    void assertPlanRejectsMissingLogicalColumn() {
         MCPMetadataQueryFacade metadataQueryFacade = createMetadataQueryFacade();
         when(metadataQueryFacade.queryTableColumn(any(), any(), any(), any())).thenReturn(Optional.empty());
         EncryptWorkflowPlanningService service = createService(mock(EncryptRuleInspectionService.class), mock(EncryptAlgorithmRecommendationService.class),
@@ -94,7 +94,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRejectsLifecycleMismatchForCreate() throws ReflectiveOperationException {
+    void assertPlanRejectsLifecycleMismatchForCreate() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of(Map.of("logic_column", "phone")));
         EncryptWorkflowPlanningService service = createService(ruleInspectionService, mock(EncryptAlgorithmRecommendationService.class),
@@ -106,7 +106,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanDropWorkflow() throws ReflectiveOperationException {
+    void assertPlanDropWorkflow() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of(Map.of("logic_column", "phone")));
         EncryptRuleDistSQLPlanningService ruleDistSQLPlanningService = mock(EncryptRuleDistSQLPlanningService.class);
@@ -125,7 +125,7 @@ class EncryptWorkflowPlanningServiceTest {
     @ParameterizedTest(name = "{0}")
     @MethodSource("assertPlanWithNaturalLanguageInferenceArguments")
     void assertPlanWithNaturalLanguageInference(final String name, final String naturalLanguageIntent, final boolean ruleExists,
-                                                final String expectedOperationType, final String expectedFieldSemantics, final String expectedStatus) throws ReflectiveOperationException {
+                                                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)));
@@ -143,7 +143,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanStopsOnBlockingAlgorithmIssue() throws ReflectiveOperationException {
+    void assertPlanStopsOnBlockingAlgorithmIssue() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of());
         when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(List.of());
@@ -161,7 +161,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRequiresExplicitCipherColumn() throws ReflectiveOperationException {
+    void assertPlanRequiresExplicitCipherColumn() {
         EncryptWorkflowRequest request = createRequest("create");
         request.getOptions().setCipherColumnName("");
         WorkflowContextSnapshot actual = planWithPrimaryCandidate(request);
@@ -171,7 +171,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRequiresExplicitEqualityInputs() throws ReflectiveOperationException {
+    void assertPlanRequiresExplicitEqualityInputs() {
         EncryptWorkflowRequest request = createRequest("create");
         request.getOptions().setRequiresEqualityFilter(true);
         request.getOptions().setAssistedQueryColumnName("");
@@ -183,7 +183,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanDoesNotApplyLikeQueryCandidateWithoutExplicitInput() throws ReflectiveOperationException {
+    void assertPlanDoesNotApplyLikeQueryCandidateWithoutExplicitInput() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of());
         when(ruleInspectionService.queryEncryptAlgorithms(any())).thenReturn(List.of(
@@ -201,7 +201,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanCreatesRuleArtifactsOnly() throws ReflectiveOperationException {
+    void assertPlanCreatesRuleArtifactsOnly() {
         EncryptWorkflowRequest request = createRequest("create");
         WorkflowContextSnapshot actual = planWithPrimaryCandidate(request);
         assertThat(actual.getStatus(), is("planned"));
@@ -211,7 +211,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanEncryptRuleWithReservedColumnAndDefaultDigest() throws ReflectiveOperationException {
+    void assertPlanEncryptRuleWithReservedColumnAndDefaultDigest() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of());
         EncryptWorkflowRequest request = createRequest("create");
@@ -230,7 +230,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRejectsAddingColumnToExistingTableRule() throws ReflectiveOperationException {
+    void assertPlanRejectsAddingColumnToExistingTableRule() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of(
                 Map.of("logic_column", "email", "cipher_column", "email_cipher", "encryptor_type", "AES", "encryptor_props", "aes-key-value=old")));
@@ -244,7 +244,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRejectsDroppingColumnFromExistingTableRule() throws ReflectiveOperationException {
+    void assertPlanRejectsDroppingColumnFromExistingTableRule() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of(
                 Map.of("logic_column", "phone", "cipher_column", "phone_cipher"),
@@ -258,7 +258,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRejectsUnsupportedOperationType() throws ReflectiveOperationException {
+    void assertPlanRejectsUnsupportedOperationType() {
         EncryptWorkflowRequest request = createRequest("replace");
         WorkflowContextSnapshot actual = createService(mock(EncryptRuleInspectionService.class), mock(EncryptAlgorithmRecommendationService.class),
                 mock(EncryptAlgorithmPropertyTemplateService.class), mock(EncryptRuleDistSQLPlanningService.class))
@@ -271,7 +271,7 @@ class EncryptWorkflowPlanningServiceTest {
     }
     
     @Test
-    void assertPlanRequiresMissingProperties() throws ReflectiveOperationException {
+    void assertPlanRequiresMissingProperties() {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of());
         EncryptAlgorithmPropertyTemplateService propertyTemplateService = mock(EncryptAlgorithmPropertyTemplateService.class);
@@ -283,7 +283,7 @@ class EncryptWorkflowPlanningServiceTest {
         assertThat(actual.getClarifiedIntent().getClarificationMessages().getFirst(), is("Please provide property `aes-key-value`."));
     }
     
-    private WorkflowContextSnapshot planWithPrimaryCandidate(final EncryptWorkflowRequest request) throws ReflectiveOperationException {
+    private WorkflowContextSnapshot planWithPrimaryCandidate(final EncryptWorkflowRequest request) {
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of());
         return createService(ruleInspectionService, createPrimaryCandidateRecommendation(), createEmptyPropertyTemplateService(), new EncryptRuleDistSQLPlanningService())
@@ -360,13 +360,17 @@ class EncryptWorkflowPlanningServiceTest {
     private EncryptWorkflowPlanningService createService(final EncryptRuleInspectionService ruleInspectionService,
                                                          final EncryptAlgorithmRecommendationService algorithmRecommendationService,
                                                          final EncryptAlgorithmPropertyTemplateService algorithmPropertyTemplateService,
-                                                         final EncryptRuleDistSQLPlanningService ruleDistSQLPlanningService) throws ReflectiveOperationException {
+                                                         final EncryptRuleDistSQLPlanningService ruleDistSQLPlanningService) {
         EncryptWorkflowPlanningService result = new EncryptWorkflowPlanningService();
-        setField(result, "ruleInspectionService", ruleInspectionService);
-        setField(result, "algorithmRecommendationService", algorithmRecommendationService);
-        setField(result, "algorithmPropertyTemplateService", algorithmPropertyTemplateService);
-        setField(result, "ruleDistSQLPlanningService", ruleDistSQLPlanningService);
-        return result;
+        try {
+            setField(result, "ruleInspectionService", ruleInspectionService);
+            setField(result, "algorithmRecommendationService", algorithmRecommendationService);
+            setField(result, "algorithmPropertyTemplateService", algorithmPropertyTemplateService);
+            setField(result, "ruleDistSQLPlanningService", ruleDistSQLPlanningService);
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
diff --git a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowValidationServiceTest.java b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowValidationServiceTest.java
index c5df084706b..99c51c50691 100644
--- a/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowValidationServiceTest.java
+++ b/mcp/features/encrypt/src/test/java/org/apache/shardingsphere/mcp/feature/encrypt/tool/service/EncryptWorkflowValidationServiceTest.java
@@ -60,7 +60,7 @@ import static org.mockito.Mockito.when;
 class EncryptWorkflowValidationServiceTest {
     
     @Test
-    void assertValidateRejectsDifferentSession() throws ReflectiveOperationException {
+    void assertValidateRejectsDifferentSession() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         workflowSessionContext.save(createSnapshot("plan-1", "session-1", "executed", "create"));
         Map<String, Object> actual = createService(mock(EncryptRuleInspectionService.class))
@@ -71,7 +71,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateHappyPath() throws ReflectiveOperationException {
+    void assertValidateHappyPath() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         workflowSessionContext.save(snapshot);
@@ -144,7 +144,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertSynchronize() throws ReflectiveOperationException {
+    void assertSynchronize() {
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         EncryptRuleInspectionService ruleInspectionService = mock(EncryptRuleInspectionService.class);
         when(ruleInspectionService.queryEncryptRules(any(), any(), any())).thenReturn(List.of(createRuleRow()));
@@ -167,7 +167,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateDropWorkflowAfterRuleRemoval() throws ReflectiveOperationException {
+    void assertValidateDropWorkflowAfterRuleRemoval() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "drop");
         workflowSessionContext.save(snapshot);
@@ -180,7 +180,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateWhenRuleMissing() throws ReflectiveOperationException {
+    void assertValidateWhenRuleMissing() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         workflowSessionContext.save(snapshot);
@@ -193,7 +193,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateWhenRuleMappingMismatch() throws ReflectiveOperationException {
+    void assertValidateWhenRuleMappingMismatch() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         workflowSessionContext.save(snapshot);
@@ -210,7 +210,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateMasksSecretPropertyMismatch() throws ReflectiveOperationException {
+    void assertValidateExpectedStateMasksSecretPropertyMismatch() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getPropertyRequirements().add(new AlgorithmPropertyRequirement("primary", "aes-key-value", true, true, "key", ""));
@@ -235,7 +235,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateAcceptsResolvedReferencedProperty() throws ReflectiveOperationException {
+    void assertValidateExpectedStateAcceptsResolvedReferencedProperty() {
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getRequest().getPrimaryAlgorithmProperties().put("aes-key-value", "secret_reference:primary.aes-key-value");
         snapshot.getRequest().getPrimaryAlgorithmSecretReferences().put("aes-key-value", SecretReferenceValue.create());
@@ -262,7 +262,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateDetectsUnresolvedReferencedProperty() throws ReflectiveOperationException {
+    void assertValidateExpectedStateDetectsUnresolvedReferencedProperty() {
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getRequest().getPrimaryAlgorithmProperties().put("aes-key-value", "secret_reference:primary.aes-key-value");
         snapshot.getRequest().getPrimaryAlgorithmSecretReferences().put("aes-key-value", SecretReferenceValue.create());
@@ -288,7 +288,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateDetectsMissingNonTargetRule() throws ReflectiveOperationException {
+    void assertValidateExpectedStateDetectsMissingNonTargetRule() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.setFeatureData(new RuleWorkflowFeatureData(List.of(), List.of(
@@ -304,7 +304,7 @@ class EncryptWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateDetectsUnexpectedExtraRule() throws ReflectiveOperationException {
+    void assertValidateExpectedStateDetectsUnexpectedExtraRule() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.setFeatureData(new RuleWorkflowFeatureData(List.of(), List.of(createRuleRow())));
@@ -319,11 +319,15 @@ class EncryptWorkflowValidationServiceTest {
         assertThat(((Map<?, ?>) ((List<?>) actual.get("mismatches")).getFirst()).get("actual"), is("logic_column=email"));
     }
     
-    private EncryptWorkflowValidationService createService(final EncryptRuleInspectionService ruleInspectionService) throws ReflectiveOperationException {
+    private EncryptWorkflowValidationService createService(final EncryptRuleInspectionService ruleInspectionService) {
         EncryptWorkflowValidationService result = new EncryptWorkflowValidationService();
-        setField(result, "ruleInspectionService", ruleInspectionService);
-        setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
-        return result;
+        try {
+            setField(result, "ruleInspectionService", ruleInspectionService);
+            setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
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 a8ca0eee411..d8dba540c68 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
@@ -24,7 +24,7 @@ import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskRuleInspectio
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.junit.jupiter.api.Test;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
 import java.util.Collection;
 import java.util.List;
@@ -33,6 +33,7 @@ import java.util.Map;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -49,17 +50,17 @@ class MaskAlgorithmsHandlerTest {
     }
     
     @Test
-    void assertHandle() throws ReflectiveOperationException {
-        MaskAlgorithmsHandler handler = new MaskAlgorithmsHandler();
-        MaskRuleInspectionService ruleInspectionService = mock(MaskRuleInspectionService.class);
+    void assertHandle() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         MCPDatabaseHandlerContext databaseContext = mock(MCPDatabaseHandlerContext.class);
         when(databaseContext.getQueryFacade()).thenReturn(queryFacade);
-        when(ruleInspectionService.queryMaskAlgorithms(queryFacade)).thenReturn(List.of(Map.of("type", "MD5")));
-        Plugins.getMemberAccessor().set(MaskAlgorithmsHandler.class.getDeclaredField("ruleInspectionService"), handler, ruleInspectionService);
-        MCPResponse actual = handler.handle(databaseContext, new MCPUriVariables(Map.of()));
-        verify(ruleInspectionService).queryMaskAlgorithms(queryFacade);
-        assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
-        assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/mask/algorithms"));
+        try (
+                MockedConstruction<MaskRuleInspectionService> mockedConstruction = mockConstruction(MaskRuleInspectionService.class,
+                        (mock, context) -> when(mock.queryMaskAlgorithms(queryFacade)).thenReturn(List.of(Map.of("type", "MD5"))))) {
+            MCPResponse actual = new MaskAlgorithmsHandler().handle(databaseContext, new MCPUriVariables(Map.of()));
+            verify(mockedConstruction.constructed().getFirst()).queryMaskAlgorithms(queryFacade);
+            assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
+            assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/mask/algorithms"));
+        }
     }
 }
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRuleHandlerTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRuleHandlerTest.java
index 7e75a83eee2..13ca566de2a 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRuleHandlerTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRuleHandlerTest.java
@@ -24,7 +24,7 @@ import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskRuleInspectio
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.junit.jupiter.api.Test;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
 import java.util.Collection;
 import java.util.List;
@@ -33,6 +33,7 @@ import java.util.Map;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -49,18 +50,18 @@ class MaskRuleHandlerTest {
     }
     
     @Test
-    void assertHandle() throws ReflectiveOperationException {
-        MaskRuleHandler handler = new MaskRuleHandler();
-        MaskRuleInspectionService ruleInspectionService = mock(MaskRuleInspectionService.class);
+    void assertHandle() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         MCPDatabaseHandlerContext databaseContext = mock(MCPDatabaseHandlerContext.class);
         when(databaseContext.getQueryFacade()).thenReturn(queryFacade);
-        when(ruleInspectionService.queryMaskRules(queryFacade, "logic_db", "orders")).thenReturn(List.of(Map.of("column", "phone")));
-        Plugins.getMemberAccessor().set(MaskRuleHandler.class.getDeclaredField("ruleInspectionService"), handler, ruleInspectionService);
-        MCPResponse actual = handler.handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db", "table", "orders")));
-        verify(ruleInspectionService).queryMaskRules(queryFacade, "logic_db", "orders");
-        assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
-        assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/mask/databases/logic_db/tables/orders/rules"));
-        assertThat(((Map<?, ?>) actual.toPayload().get("parent_resource")).get("uri"), is("shardingsphere://features/mask/databases/logic_db/rules"));
+        try (
+                MockedConstruction<MaskRuleInspectionService> mockedConstruction = mockConstruction(MaskRuleInspectionService.class,
+                        (mock, context) -> when(mock.queryMaskRules(queryFacade, "logic_db", "orders")).thenReturn(List.of(Map.of("column", "phone"))))) {
+            MCPResponse actual = new MaskRuleHandler().handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db", "table", "orders")));
+            verify(mockedConstruction.constructed().getFirst()).queryMaskRules(queryFacade, "logic_db", "orders");
+            assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
+            assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/mask/databases/logic_db/tables/orders/rules"));
+            assertThat(((Map<?, ?>) actual.toPayload().get("parent_resource")).get("uri"), is("shardingsphere://features/mask/databases/logic_db/rules"));
+        }
     }
 }
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRulesHandlerTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRulesHandlerTest.java
index 0f1a70c5ecb..5307c01364d 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRulesHandlerTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/resource/handler/MaskRulesHandlerTest.java
@@ -24,7 +24,7 @@ import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskRuleInspectio
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureQueryFacade;
 import org.junit.jupiter.api.Test;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
 import java.util.Collection;
 import java.util.List;
@@ -33,6 +33,7 @@ import java.util.Map;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -49,17 +50,17 @@ class MaskRulesHandlerTest {
     }
     
     @Test
-    void assertHandle() throws ReflectiveOperationException {
-        MaskRulesHandler handler = new MaskRulesHandler();
-        MaskRuleInspectionService ruleInspectionService = mock(MaskRuleInspectionService.class);
+    void assertHandle() {
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         MCPDatabaseHandlerContext databaseContext = mock(MCPDatabaseHandlerContext.class);
         when(databaseContext.getQueryFacade()).thenReturn(queryFacade);
-        when(ruleInspectionService.queryMaskRules(queryFacade, "logic_db")).thenReturn(List.of(Map.of("column", "phone")));
-        Plugins.getMemberAccessor().set(MaskRulesHandler.class.getDeclaredField("ruleInspectionService"), handler, ruleInspectionService);
-        MCPResponse actual = handler.handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db")));
-        verify(ruleInspectionService).queryMaskRules(queryFacade, "logic_db");
-        assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
-        assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/mask/databases/logic_db/rules"));
+        try (
+                MockedConstruction<MaskRuleInspectionService> mockedConstruction = mockConstruction(MaskRuleInspectionService.class,
+                        (mock, context) -> when(mock.queryMaskRules(queryFacade, "logic_db")).thenReturn(List.of(Map.of("column", "phone"))))) {
+            MCPResponse actual = new MaskRulesHandler().handle(databaseContext, new MCPUriVariables(Map.of("database", "logic_db")));
+            verify(mockedConstruction.constructed().getFirst()).queryMaskRules(queryFacade, "logic_db");
+            assertThat(((Collection<?>) actual.toPayload().get("items")).size(), is(1));
+            assertThat(actual.toPayload().get("self_uri"), is("shardingsphere://features/mask/databases/logic_db/rules"));
+        }
     }
 }
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/handler/MaskToolHandlerTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/handler/MaskToolHandlerTest.java
index e2038268d88..5bee34790f3 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/handler/MaskToolHandlerTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/handler/MaskToolHandlerTest.java
@@ -21,7 +21,6 @@ import org.apache.shardingsphere.mcp.api.protocol.response.MCPResponse;
 import org.apache.shardingsphere.mcp.api.tool.MCPToolCall;
 import org.apache.shardingsphere.mcp.feature.mask.MaskFeatureDefinition;
 import org.apache.shardingsphere.mcp.feature.mask.TestWorkflowSessionContext;
-import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskAlgorithmPropertyTemplateService;
 import org.apache.shardingsphere.mcp.feature.mask.tool.service.MaskWorkflowPlanningService;
 import org.apache.shardingsphere.mcp.support.database.MCPDatabaseHandlerContext;
 import org.apache.shardingsphere.mcp.support.database.spi.MCPFeatureExecutionFacade;
@@ -37,9 +36,8 @@ import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowContextSnaps
 import org.apache.shardingsphere.mcp.support.workflow.model.WorkflowRequest;
 import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
-import org.mockito.internal.configuration.plugins.Plugins;
+import org.mockito.MockedConstruction;
 
-import java.lang.reflect.Field;
 import java.util.List;
 import java.util.Map;
 
@@ -50,81 +48,81 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 class MaskToolHandlerTest {
     
     @Test
-    void assertHandlePlanMaskRule() throws ReflectiveOperationException {
-        PlanMaskRuleToolHandler handler = new PlanMaskRuleToolHandler();
-        MaskWorkflowPlanningService planningService = mock(MaskWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
-        setField(handler, "planningService", planningService);
-        setField(handler, "propertyTemplateService", new MaskAlgorithmPropertyTemplateService());
-        WorkflowContextFixture fixture = createWorkflowContextFixture();
-        MCPResponse actual = handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
-                "database", "logic_db",
-                "table", "orders",
-                "column", "phone",
-                "algorithm_type", "KEEP_FIRST_N_LAST_M",
-                "structured_intent_evidence", Map.of("field_semantics", "phone"))));
-        assertThat(actual.toPayload().get("plan_id"), is("plan-1"));
-        ArgumentCaptor<WorkflowRequest> requestCaptor = ArgumentCaptor.forClass(WorkflowRequest.class);
-        verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
-        WorkflowRequest actualRequest = requestCaptor.getValue();
-        assertThat(actualRequest.getAlgorithmType(), is("KEEP_FIRST_N_LAST_M"));
-        assertThat(actualRequest.getFieldSemantics(), is("phone"));
+    void assertHandlePlanMaskRule() {
+        try (MockedConstruction<MaskWorkflowPlanningService> mockedConstruction = mockConstruction(MaskWorkflowPlanningService.class)) {
+            PlanMaskRuleToolHandler handler = new PlanMaskRuleToolHandler();
+            MaskWorkflowPlanningService planningService = mockedConstruction.constructed().getFirst();
+            when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
+            WorkflowContextFixture fixture = createWorkflowContextFixture();
+            MCPResponse actual = handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
+                    "database", "logic_db",
+                    "table", "orders",
+                    "column", "phone",
+                    "algorithm_type", "KEEP_FIRST_N_LAST_M",
+                    "structured_intent_evidence", Map.of("field_semantics", "phone"))));
+            assertThat(actual.toPayload().get("plan_id"), is("plan-1"));
+            ArgumentCaptor<WorkflowRequest> requestCaptor = ArgumentCaptor.forClass(WorkflowRequest.class);
+            verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
+            WorkflowRequest actualRequest = requestCaptor.getValue();
+            assertThat(actualRequest.getAlgorithmType(), is("KEEP_FIRST_N_LAST_M"));
+            assertThat(actualRequest.getFieldSemantics(), is("phone"));
+        }
     }
     
     @Test
-    void assertHandlePlanMaskRuleWithMaskedArtifacts() throws ReflectiveOperationException {
-        PlanMaskRuleToolHandler handler = new PlanMaskRuleToolHandler();
-        MaskWorkflowPlanningService planningService = mock(MaskWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createDetailedSnapshot());
-        setField(handler, "planningService", planningService);
-        setField(handler, "propertyTemplateService", new MaskAlgorithmPropertyTemplateService());
-        MCPResponse actual = handler.handle(createWorkflowContextFixture().workflowContext, new MCPToolCall("session-1", Map.of(
-                "database", "logic_db",
-                "table", "orders",
-                "column", "phone")));
-        Map<String, Object> actualPayload = actual.toPayload();
-        assertThat(((Map<?, ?>) ((Map<?, ?>) actualPayload.get("masked_property_preview")).get("primary")).get("first-n"), is("3"));
-        assertFalse(actualPayload.containsKey("ddl_artifacts"));
-        assertFalse(actualPayload.containsKey("index_plan"));
-        assertTrue(String.valueOf(((Map<?, ?>) ((List<?>) actualPayload.get("distsql_artifacts")).getFirst()).get("sql")).contains("keep_first_n_last_m"));
-        List<?> actualResourcesToRead = (List<?>) actualPayload.get("resources_to_read");
-        List<String> actualResourceUris = extractResourceUris(actualResourcesToRead);
-        assertTrue(actualResourceUris.contains("shardingsphere://features/mask/algorithms"));
-        assertTrue(actualResourceUris.contains("shardingsphere://features/mask/databases/logic_db/rules"));
-        assertTrue(actualResourceUris.contains("shardingsphere://features/mask/databases/logic_db/tables/orders/rules"));
-        assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/mask/algorithms"), is("algorithm"));
-        assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/mask/databases/logic_db/rules"), is("rule"));
-        assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/mask/databases/logic_db/tables/orders/rules"), is("rule"));
-        assertFalse(actualResourceUris.contains("shardingsphere://databases/logic_db/schemas/public/tables/orders/columns"));
-        Map<?, ?> actualNextAction = (Map<?, ?>) ((List<?>) actualPayload.get("next_actions")).getFirst();
-        assertThat(actualNextAction.get("type"), is("tool_call"));
-        assertThat(actualNextAction.get("tool_name"), is("database_gateway_apply_workflow"));
-        assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("plan_id"), is("plan-1"));
-        assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("execution_mode"), is("preview"));
+    void assertHandlePlanMaskRuleWithMaskedArtifacts() {
+        try (MockedConstruction<MaskWorkflowPlanningService> mockedConstruction = mockConstruction(MaskWorkflowPlanningService.class)) {
+            PlanMaskRuleToolHandler handler = new PlanMaskRuleToolHandler();
+            when(mockedConstruction.constructed().getFirst().plan(any(), any(), any(), any(), any())).thenReturn(createDetailedSnapshot());
+            MCPResponse actual = handler.handle(createWorkflowContextFixture().workflowContext, new MCPToolCall("session-1", Map.of(
+                    "database", "logic_db",
+                    "table", "orders",
+                    "column", "phone")));
+            Map<String, Object> actualPayload = actual.toPayload();
+            assertThat(((Map<?, ?>) ((Map<?, ?>) actualPayload.get("masked_property_preview")).get("primary")).get("first-n"), is("3"));
+            assertFalse(actualPayload.containsKey("ddl_artifacts"));
+            assertFalse(actualPayload.containsKey("index_plan"));
+            assertTrue(String.valueOf(((Map<?, ?>) ((List<?>) actualPayload.get("distsql_artifacts")).getFirst()).get("sql")).contains("keep_first_n_last_m"));
+            List<?> actualResourcesToRead = (List<?>) actualPayload.get("resources_to_read");
+            List<String> actualResourceUris = extractResourceUris(actualResourcesToRead);
+            assertTrue(actualResourceUris.contains("shardingsphere://features/mask/algorithms"));
+            assertTrue(actualResourceUris.contains("shardingsphere://features/mask/databases/logic_db/rules"));
+            assertTrue(actualResourceUris.contains("shardingsphere://features/mask/databases/logic_db/tables/orders/rules"));
+            assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/mask/algorithms"), is("algorithm"));
+            assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/mask/databases/logic_db/rules"), is("rule"));
+            assertThat(findResourceKind(actualResourcesToRead, "shardingsphere://features/mask/databases/logic_db/tables/orders/rules"), is("rule"));
+            assertFalse(actualResourceUris.contains("shardingsphere://databases/logic_db/schemas/public/tables/orders/columns"));
+            Map<?, ?> actualNextAction = (Map<?, ?>) ((List<?>) actualPayload.get("next_actions")).getFirst();
+            assertThat(actualNextAction.get("type"), is("tool_call"));
+            assertThat(actualNextAction.get("tool_name"), is("database_gateway_apply_workflow"));
+            assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("plan_id"), is("plan-1"));
+            assertThat(((Map<?, ?>) actualNextAction.get("arguments")).get("execution_mode"), is("preview"));
+        }
     }
     
     @Test
-    void assertHandlePlanMaskRuleWithSecretReference() throws ReflectiveOperationException {
-        PlanMaskRuleToolHandler handler = new PlanMaskRuleToolHandler();
-        MaskWorkflowPlanningService planningService = mock(MaskWorkflowPlanningService.class);
-        when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
-        setField(handler, "planningService", planningService);
-        setField(handler, "propertyTemplateService", new MaskAlgorithmPropertyTemplateService());
-        WorkflowContextFixture fixture = createWorkflowContextFixture();
-        handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
-                "database", "logic_db",
-                "primary_algorithm_properties", Map.of("replace-char", Map.of("secret_ref", "placeholder://secret-value-1")))));
-        ArgumentCaptor<WorkflowRequest> requestCaptor = ArgumentCaptor.forClass(WorkflowRequest.class);
-        verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
-        WorkflowRequest actualRequest = requestCaptor.getValue();
-        assertThat(actualRequest.getPrimaryAlgorithmProperties().get("replace-char"), is("secret_reference:primary.replace-char"));
-        assertFalse(actualRequest.getSecretReferences("primary").get("replace-char").isMalformed());
+    void assertHandlePlanMaskRuleWithSecretReference() {
+        try (MockedConstruction<MaskWorkflowPlanningService> mockedConstruction = mockConstruction(MaskWorkflowPlanningService.class)) {
+            PlanMaskRuleToolHandler handler = new PlanMaskRuleToolHandler();
+            MaskWorkflowPlanningService planningService = mockedConstruction.constructed().getFirst();
+            when(planningService.plan(any(), any(), any(), any(), any())).thenReturn(createSnapshot("plan-1", "planned"));
+            WorkflowContextFixture fixture = createWorkflowContextFixture();
+            handler.handle(fixture.workflowContext, new MCPToolCall("session-1", Map.of(
+                    "database", "logic_db",
+                    "primary_algorithm_properties", Map.of("replace-char", Map.of("secret_ref", "placeholder://secret-value-1")))));
+            ArgumentCaptor<WorkflowRequest> requestCaptor = ArgumentCaptor.forClass(WorkflowRequest.class);
+            verify(planningService).plan(eq(fixture.workflowSessionContext), eq(fixture.metadataQueryFacade), eq(fixture.queryFacade), eq("session-1"), requestCaptor.capture());
+            WorkflowRequest actualRequest = requestCaptor.getValue();
+            assertThat(actualRequest.getPrimaryAlgorithmProperties().get("replace-char"), is("secret_reference:primary.replace-char"));
+            assertFalse(actualRequest.getSecretReferences("primary").get("replace-char").isMalformed());
+        }
     }
     
     private WorkflowContextSnapshot createSnapshot(final String planId, final String status) {
@@ -162,11 +160,6 @@ class MaskToolHandlerTest {
         return result;
     }
     
-    private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
-        Field field = target.getClass().getDeclaredField(fieldName);
-        Plugins.getMemberAccessor().set(field, target, value);
-    }
-    
     private List<String> extractResourceUris(final List<?> resources) {
         return resources.stream().map(each -> (String) ((Map<?, ?>) each).get("uri")).toList();
     }
diff --git a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowValidationServiceTest.java b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowValidationServiceTest.java
index 178cf9f447d..7847753104b 100644
--- a/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowValidationServiceTest.java
+++ b/mcp/features/mask/src/test/java/org/apache/shardingsphere/mcp/feature/mask/tool/service/MaskWorkflowValidationServiceTest.java
@@ -58,7 +58,7 @@ import static org.mockito.Mockito.when;
 class MaskWorkflowValidationServiceTest {
     
     @Test
-    void assertValidateRejectsDifferentSession() throws ReflectiveOperationException {
+    void assertValidateRejectsDifferentSession() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         workflowSessionContext.save(createSnapshot("plan-1", "session-1", "executed", "create"));
         Map<String, Object> actual = createService(mock(MaskRuleInspectionService.class))
@@ -69,7 +69,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateHappyPath() throws ReflectiveOperationException {
+    void assertValidateHappyPath() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getRequest().setAlgorithmType("MASK_FROM_X_TO_Y");
@@ -120,7 +120,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertSynchronize() throws ReflectiveOperationException {
+    void assertSynchronize() {
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getRequest().setAlgorithmType("MASK_FROM_X_TO_Y");
         MaskRuleInspectionService ruleInspectionService = mock(MaskRuleInspectionService.class);
@@ -145,7 +145,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateDropWorkflowAfterRuleRemoval() throws ReflectiveOperationException {
+    void assertValidateDropWorkflowAfterRuleRemoval() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "drop");
         workflowSessionContext.save(snapshot);
@@ -158,7 +158,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateWhenAlgorithmMismatch() throws ReflectiveOperationException {
+    void assertValidateWhenAlgorithmMismatch() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getRequest().setAlgorithmType("MASK_FROM_X_TO_Y");
@@ -172,7 +172,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateDetectsPropertyMismatch() throws ReflectiveOperationException {
+    void assertValidateExpectedStateDetectsPropertyMismatch() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.setFeatureData(new RuleWorkflowFeatureData(List.of(), List.of(Map.of(
@@ -192,7 +192,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateAcceptsResolvedReferencedProperty() throws ReflectiveOperationException {
+    void assertValidateExpectedStateAcceptsResolvedReferencedProperty() {
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getRequest().getPrimaryAlgorithmProperties().put("replace-char", "secret_reference:primary.replace-char");
         snapshot.getRequest().getPrimaryAlgorithmSecretReferences().put("replace-char", SecretReferenceValue.create());
@@ -217,7 +217,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateDetectsUnresolvedReferencedProperty() throws ReflectiveOperationException {
+    void assertValidateExpectedStateDetectsUnresolvedReferencedProperty() {
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.getRequest().getPrimaryAlgorithmProperties().put("replace-char", "secret_reference:primary.replace-char");
         snapshot.getRequest().getPrimaryAlgorithmSecretReferences().put("replace-char", SecretReferenceValue.create());
@@ -241,7 +241,7 @@ class MaskWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateExpectedStateDetectsMissingNonTargetRule() throws ReflectiveOperationException {
+    void assertValidateExpectedStateDetectsMissingNonTargetRule() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create");
         snapshot.setFeatureData(new RuleWorkflowFeatureData(List.of(), List.of(
@@ -256,11 +256,15 @@ class MaskWorkflowValidationServiceTest {
         assertThat(((Map<?, ?>) ((List<?>) actual.get("mismatches")).getFirst()).get("expected"), is("column=email"));
     }
     
-    private MaskWorkflowValidationService createService(final MaskRuleInspectionService ruleInspectionService) throws ReflectiveOperationException {
+    private MaskWorkflowValidationService createService(final MaskRuleInspectionService ruleInspectionService) {
         MaskWorkflowValidationService result = new MaskWorkflowValidationService();
-        setField(result, "ruleInspectionService", ruleInspectionService);
-        setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
-        return result;
+        try {
+            setField(result, "ruleInspectionService", ruleInspectionService);
+            setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
diff --git a/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/tool/service/ReadwriteSplittingWorkflowValidationServiceTest.java b/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/tool/service/ReadwriteSplittingWorkflowValidationServiceTest.java
index 28d615e9136..f4bcc1b1322 100644
--- a/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/tool/service/ReadwriteSplittingWorkflowValidationServiceTest.java
+++ b/mcp/features/readwrite-splitting/src/test/java/org/apache/shardingsphere/mcp/feature/readwritesplitting/tool/service/ReadwriteSplittingWorkflowValidationServiceTest.java
@@ -55,7 +55,7 @@ import static org.mockito.Mockito.when;
 class ReadwriteSplittingWorkflowValidationServiceTest {
     
     @Test
-    void assertValidateRejectsDifferentSession() throws ReflectiveOperationException {
+    void assertValidateRejectsDifferentSession() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         workflowSessionContext.save(createRuleSnapshot("plan-1", "session-1", "executed", "create"));
         Map<String, Object> actual = createRuleService(mock(ReadwriteSplittingInspectionService.class))
@@ -66,7 +66,7 @@ class ReadwriteSplittingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateRuleHappyPath() throws ReflectiveOperationException {
+    void assertValidateRuleHappyPath() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createRuleSnapshot("plan-1", "session-1", "executed", "create");
         workflowSessionContext.save(snapshot);
@@ -112,7 +112,7 @@ class ReadwriteSplittingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateRuleMismatch() throws ReflectiveOperationException {
+    void assertValidateRuleMismatch() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createRuleSnapshot("plan-1", "session-1", "executed", "create");
         workflowSessionContext.save(snapshot);
@@ -125,7 +125,7 @@ class ReadwriteSplittingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateDropWorkflowAfterRuleRemoval() throws ReflectiveOperationException {
+    void assertValidateDropWorkflowAfterRuleRemoval() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createRuleSnapshot("plan-1", "session-1", "executed", "drop");
         workflowSessionContext.save(snapshot);
@@ -137,7 +137,7 @@ class ReadwriteSplittingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateStatusHappyPath() throws ReflectiveOperationException {
+    void assertValidateStatusHappyPath() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createStatusSnapshot("plan-1", "session-1", "executed", "enable");
         workflowSessionContext.save(snapshot);
@@ -162,18 +162,26 @@ class ReadwriteSplittingWorkflowValidationServiceTest {
         assertThat(actual.getIssueCode(), is(WorkflowIssueCode.RULE_STATE_MISMATCH));
     }
     
-    private ReadwriteSplittingRuleWorkflowValidationService createRuleService(final ReadwriteSplittingInspectionService inspectionService) throws ReflectiveOperationException {
+    private ReadwriteSplittingRuleWorkflowValidationService createRuleService(final ReadwriteSplittingInspectionService inspectionService) {
         ReadwriteSplittingRuleWorkflowValidationService result = new ReadwriteSplittingRuleWorkflowValidationService();
-        setField(result, "inspectionService", inspectionService);
-        setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
-        return result;
+        try {
+            setField(result, "inspectionService", inspectionService);
+            setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
-    private ReadwriteSplittingStatusWorkflowValidationService createStatusService(final ReadwriteSplittingInspectionService inspectionService) throws ReflectiveOperationException {
+    private ReadwriteSplittingStatusWorkflowValidationService createStatusService(final ReadwriteSplittingInspectionService inspectionService) {
         ReadwriteSplittingStatusWorkflowValidationService result = new ReadwriteSplittingStatusWorkflowValidationService();
-        setField(result, "inspectionService", inspectionService);
-        setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
-        return result;
+        try {
+            setField(result, "inspectionService", inspectionService);
+            setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
diff --git a/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/tool/service/ShadowWorkflowValidationServiceTest.java b/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/tool/service/ShadowWorkflowValidationServiceTest.java
index 2a47738b920..9866d39fa7d 100644
--- a/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/tool/service/ShadowWorkflowValidationServiceTest.java
+++ b/mcp/features/shadow/src/test/java/org/apache/shardingsphere/mcp/feature/shadow/tool/service/ShadowWorkflowValidationServiceTest.java
@@ -51,7 +51,7 @@ import static org.mockito.Mockito.when;
 class ShadowWorkflowValidationServiceTest {
     
     @Test
-    void assertValidateRule() throws ReflectiveOperationException {
+    void assertValidateRule() {
         ShadowInspectionService inspectionService = mock(ShadowInspectionService.class);
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         when(inspectionService.queryRules(queryFacade, "logic_db")).thenReturn(List.of(Map.of(
@@ -66,7 +66,7 @@ class ShadowWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateCleanupFailure() throws ReflectiveOperationException {
+    void assertValidateCleanupFailure() {
         ShadowInspectionService inspectionService = mock(ShadowInspectionService.class);
         MCPFeatureQueryFacade queryFacade = mock(MCPFeatureQueryFacade.class);
         when(inspectionService.queryAlgorithms(queryFacade, "logic_db")).thenReturn(List.of(Map.of("shadow_algorithm_name", "unused_algorithm")));
@@ -105,11 +105,15 @@ class ShadowWorkflowValidationServiceTest {
         }
     }
     
-    private ShadowWorkflowValidationService createService(final ShadowInspectionService inspectionService) throws ReflectiveOperationException {
+    private ShadowWorkflowValidationService createService(final ShadowInspectionService inspectionService) {
         ShadowWorkflowValidationService result = new ShadowWorkflowValidationService();
-        setField(result, "inspectionService", inspectionService);
-        setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
-        return result;
+        try {
+            setField(result, "inspectionService", inspectionService);
+            setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
diff --git a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationServiceTest.java b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationServiceTest.java
index 05dea041817..df33384be26 100644
--- a/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationServiceTest.java
+++ b/mcp/features/sharding/src/test/java/org/apache/shardingsphere/mcp/feature/sharding/tool/service/ShardingWorkflowValidationServiceTest.java
@@ -57,7 +57,7 @@ import static org.mockito.Mockito.when;
 class ShardingWorkflowValidationServiceTest {
     
     @Test
-    void assertValidateRejectsDifferentSession() throws ReflectiveOperationException {
+    void assertValidateRejectsDifferentSession() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         workflowSessionContext.save(createSnapshot("plan-1", "session-1", "executed", "create", ShardingFeatureDefinition.TABLE_RULE_WORKFLOW_KIND, createTableRuleRequest()));
         Map<String, Object> actual = createService(mock(ShardingInspectionService.class)).validate(workflowSessionContext, mock(MCPMetadataQueryFacade.class),
@@ -67,7 +67,7 @@ class ShardingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateTableRuleHappyPath() throws ReflectiveOperationException {
+    void assertValidateTableRuleHappyPath() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create",
                 ShardingFeatureDefinition.TABLE_RULE_WORKFLOW_KIND, createTableRuleRequest());
@@ -135,7 +135,7 @@ class ShardingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateTableRuleMismatch() throws ReflectiveOperationException {
+    void assertValidateTableRuleMismatch() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "create",
                 ShardingFeatureDefinition.TABLE_RULE_WORKFLOW_KIND, createTableRuleRequest());
@@ -149,7 +149,7 @@ class ShardingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateDefaultStrategyDrop() throws ReflectiveOperationException {
+    void assertValidateDefaultStrategyDrop() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         ShardingWorkflowRequest request = createTableRuleRequest();
         request.setDefaultStrategyType("DATABASE");
@@ -164,7 +164,7 @@ class ShardingWorkflowValidationServiceTest {
     }
     
     @Test
-    void assertValidateCleanupHappyPath() throws ReflectiveOperationException {
+    void assertValidateCleanupHappyPath() {
         WorkflowSessionContext workflowSessionContext = new TestWorkflowSessionContext();
         WorkflowContextSnapshot snapshot = createSnapshot("plan-1", "session-1", "executed", "drop",
                 ShardingFeatureDefinition.COMPONENT_CLEANUP_WORKFLOW_KIND, createCleanupRequest());
@@ -188,11 +188,15 @@ class ShardingWorkflowValidationServiceTest {
         assertThat(actual.getIssueCode(), is(WorkflowIssueCode.RULE_STATE_MISMATCH));
     }
     
-    private ShardingWorkflowValidationService createService(final ShardingInspectionService inspectionService) throws ReflectiveOperationException {
+    private ShardingWorkflowValidationService createService(final ShardingInspectionService inspectionService) {
         ShardingWorkflowValidationService result = new ShardingWorkflowValidationService();
-        setField(result, "inspectionService", inspectionService);
-        setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
-        return result;
+        try {
+            setField(result, "inspectionService", inspectionService);
+            setField(result, "workflowSynchronizationSupport", new WorkflowSynchronizationSupport(1, 0L));
+            return result;
+        } catch (final ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
     }
     
     private void setField(final Object target, final String fieldName, final Object value) throws ReflectiveOperationException {
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 cc4cdd1e3b8..1b66a9cefdb 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
@@ -21,6 +21,7 @@ import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 import org.apache.shardingsphere.mcp.api.resource.descriptor.MCPResourceDescriptor;
+import org.apache.shardingsphere.mcp.api.tool.descriptor.MCPToolAnnotations;
 import org.apache.shardingsphere.mcp.api.tool.descriptor.MCPToolDescriptor;
 import org.apache.shardingsphere.mcp.support.protocol.MCPPayloadFieldNames;
 import org.apache.shardingsphere.mcp.support.workflow.descriptor.WorkflowToolDescriptors;
@@ -155,6 +156,7 @@ public final class MCPToolDescriptorCatalogValidator {
         }
         if (null != runtimeDescriptor && "plan".equals(runtimeDescriptor.getWorkflowRole())) {
             validatePlanningWorkflowDescriptor(descriptor);
+            validatePlanningToolAnnotations(descriptor);
         }
     }
     
@@ -297,6 +299,16 @@ public final class MCPToolDescriptorCatalogValidator {
         }
     }
     
+    private static void validatePlanningToolAnnotations(final MCPToolDescriptor descriptor) {
+        MCPToolAnnotations annotations = descriptor.getAnnotations();
+        ShardingSpherePreconditions.checkState(!annotations.isReadOnlyHint(),
+                () -> new IllegalStateException(String.format("Planning tool `%s` annotations.readOnlyHint must be false.", descriptor.getName())));
+        ShardingSpherePreconditions.checkState(!annotations.isDestructiveHint(),
+                () -> new IllegalStateException(String.format("Planning tool `%s` annotations.destructiveHint must be false.", descriptor.getName())));
+        ShardingSpherePreconditions.checkState(!annotations.isIdempotentHint(),
+                () -> new IllegalStateException(String.format("Planning tool `%s` annotations.idempotentHint must be false.", descriptor.getName())));
+    }
+    
     private static void validateDestructiveToolDescriptor(final MCPToolDescriptor descriptor, final MCPToolRuntimeDescriptor runtimeDescriptor) {
         if (!descriptor.getAnnotations().isDestructiveHint()) {
             return;
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtils.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtils.java
index 376c34c1504..16122e250a5 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtils.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtils.java
@@ -22,6 +22,7 @@ import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -171,10 +172,21 @@ public final class MCPNextActionUtils {
      */
     @SafeVarargs
     public static List<Map<String, Object>> ordered(final Map<String, Object>... actions) {
-        List<Map<String, Object>> result = new ArrayList<>(actions.length);
-        for (int index = 0; index < actions.length; index++) {
-            Map<String, Object> action = new LinkedHashMap<>(actions[index]);
-            action.put("order", index + 1);
+        return ordered(Arrays.asList(actions));
+    }
+    
+    /**
+     * Add 1-based order values to actions.
+     *
+     * @param actions actions
+     * @return ordered actions
+     */
+    public static List<Map<String, Object>> ordered(final Collection<Map<String, Object>> actions) {
+        List<Map<String, Object>> result = new ArrayList<>(actions.size());
+        int index = 0;
+        for (Map<String, Object> each : actions) {
+            Map<String, Object> action = new LinkedHashMap<>(each);
+            action.put("order", ++index);
             result.add(action);
         }
         return result;
diff --git a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowFieldNames.java b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowFieldNames.java
index 04ddf1db88b..ba4a048170c 100644
--- a/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowFieldNames.java
+++ b/mcp/support/src/main/java/org/apache/shardingsphere/mcp/support/workflow/model/WorkflowFieldNames.java
@@ -28,6 +28,8 @@ public final class WorkflowFieldNames {
     
     public static final String ALGORITHM_TYPE = "algorithm_type";
     
+    public static final String APPROVED_STEPS = "approved_steps";
+    
     public static final String ASSISTED_QUERY_ALGORITHM_PROPERTIES = "assisted_query_algorithm_properties";
     
     public static final String ASSISTED_QUERY_ALGORITHM_TYPE = "assisted_query_algorithm_type";
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 55cdc2a591d..9db5e5f9a74 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
@@ -110,7 +110,7 @@ class MCPDescriptorCatalogValidatorTest {
     @Test
     void assertValidateRejectsPlanningRuntimeWithoutWorkflowKind() {
         String toolName = "database_gateway_test_plan_rule";
-        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, new MCPToolAnnotations("Test Tool", true, false, true, true),
+        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, createPlanningToolAnnotations(),
                 createWorkflowPlanOutputSchema(), createPlanningToolMetaWithoutWorkflowKind())),
                 List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
                 "Tool `database_gateway_test_plan_rule` metadata must declare `org.apache.shardingsphere/workflow-kind`.");
@@ -118,9 +118,9 @@ class MCPDescriptorCatalogValidatorTest {
     
     @Test
     void assertValidateRejectsDuplicatePlanningWorkflowKind() {
-        MCPToolDescriptor firstTool = createToolDescriptor("database_gateway_test_plan_rule", new MCPToolAnnotations("Test Tool", true, false, true, true),
+        MCPToolDescriptor firstTool = createToolDescriptor("database_gateway_test_plan_rule", createPlanningToolAnnotations(),
                 createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"));
-        MCPToolDescriptor secondTool = createToolDescriptor("database_gateway_test_plan_rule_again", new MCPToolAnnotations("Test Tool", true, false, true, true),
+        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()),
@@ -128,6 +128,30 @@ class MCPDescriptorCatalogValidatorTest {
                 "Planning workflow kind `test.rule` is used by both `database_gateway_test_plan_rule` and `database_gateway_test_plan_rule_again`.");
     }
     
+    @Test
+    void assertValidateRejectsPlanningToolReadOnlyHint() {
+        String toolName = "database_gateway_test_plan_rule";
+        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, new MCPToolAnnotations("Test Tool", true, false, false, true),
+                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
+                "Planning tool `database_gateway_test_plan_rule` annotations.readOnlyHint must be false.");
+    }
+    
+    @Test
+    void assertValidateRejectsPlanningToolDestructiveHint() {
+        String toolName = "database_gateway_test_plan_rule";
+        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, new MCPToolAnnotations("Test Tool", false, true, false, true),
+                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
+                "Planning tool `database_gateway_test_plan_rule` annotations.destructiveHint must be false.");
+    }
+    
+    @Test
+    void assertValidateRejectsPlanningToolIdempotentHint() {
+        String toolName = "database_gateway_test_plan_rule";
+        assertValidationError(createToolRuntimeCatalog(List.of(), List.of(createToolDescriptor(toolName, new MCPToolAnnotations("Test Tool", false, false, true, true),
+                createWorkflowPlanOutputSchema(), createPlanningToolMeta("test.rule"))), List.of(new MCPToolRuntimeDescriptor(toolName, "plan", List.of()))),
+                "Planning tool `database_gateway_test_plan_rule` annotations.idempotentHint must be false.");
+    }
+    
     @Test
     void assertValidateRejectsUnsupportedNextActionSchemaField() {
         assertValidationError(createCatalog(List.of(), List.of(createToolDescriptor(
@@ -283,6 +307,10 @@ class MCPDescriptorCatalogValidatorTest {
         return new MCPToolDescriptor(toolName, "Test Tool", "Run a test tool.", createInputSchema(), outputSchema, annotations, meta);
     }
     
+    private MCPToolAnnotations createPlanningToolAnnotations() {
+        return new MCPToolAnnotations("Test Tool", false, false, false, true);
+    }
+    
     private Map<String, Object> createInputSchema() {
         return createInputSchema(Map.of("query", Map.of("type", "string", "description", "Query.")));
     }
diff --git a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtilsTest.java b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtilsTest.java
index f943c8905c4..65c450fcf0d 100644
--- a/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtilsTest.java
+++ b/mcp/support/src/test/java/org/apache/shardingsphere/mcp/support/protocol/MCPNextActionUtilsTest.java
@@ -121,6 +121,15 @@ class MCPNextActionUtilsTest {
         assertFalse(action.containsKey("order"));
     }
     
+    @Test
+    void assertOrderedCollectionCopiesActions() {
+        Map<String, Object> action = Map.of("type", "terminal");
+        List<Map<String, Object>> actual = MCPNextActionUtils.ordered(List.of(action, Map.of("type", "tool_call")));
+        assertThat(actual.get(0).get("order"), is(1));
+        assertThat(actual.get(1).get("order"), is(2));
+        assertFalse(action.containsKey("order"));
+    }
+    
     @Test
     void assertDependsOnCopiesAction() {
         Map<String, Object> action = Map.of("type", "tool_call");
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunner.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunner.java
index d657b4bbfdb..8860f88e89e 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunner.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunner.java
@@ -78,7 +78,7 @@ final class LLMUsabilitySuiteRunner {
                              final ConversationRunner conversationRunner, final LLME2EConfiguration configuration) throws IOException {
         EvaluatedSuite evaluatedSuite = evaluateSuite(suiteId, scenarioSupplier, conversationRunner, configuration);
         assumeModelServiceAvailable(evaluatedSuite.scorecard());
-        assertFullScore(evaluatedSuite.scorecard(), evaluatedSuite.scenarios());
+        assertFullScore(evaluatedSuite);
         assertDeterministicContract(evaluatedSuite);
     }
     
@@ -117,11 +117,12 @@ final class LLMUsabilitySuiteRunner {
         return Optional.empty();
     }
     
-    private void assertFullScore(final LLMUsabilityScorecard scorecard, final List<LLMUsabilityScenario> scenarios) {
-        String actualFailureSummary = createFailureSummary(scorecard);
+    private void assertFullScore(final EvaluatedSuite evaluatedSuite) {
+        LLMUsabilityScorecard scorecard = evaluatedSuite.scorecard();
+        String actualFailureSummary = createFailureSummary(evaluatedSuite);
         assertThat(actualFailureSummary, scorecard.getOverallScore(), is(100.0D));
         assertTrue(scorecard.isFullScore(), actualFailureSummary);
-        assertThat(actualFailureSummary, scorecard.getScenarioResults().size(), is(scenarios.size()));
+        assertThat(actualFailureSummary, scorecard.getScenarioResults().size(), is(evaluatedSuite.scenarios().size()));
         assertThat(actualFailureSummary, scorecard.getTaskSuccessRate(), is(1.0D));
         assertThat(actualFailureSummary, scorecard.getNaturalTaskSuccessRate(), is(1.0D));
         assertThat(actualFailureSummary, scorecard.getProtocolContractSuccessRate(), is(1.0D));
@@ -133,10 +134,10 @@ final class LLMUsabilitySuiteRunner {
         assertThat(actualFailureSummary, scorecard.getApprovalViolationRate(), is(0.0D));
         assertThat(actualFailureSummary, scorecard.getNativeToolCallRate(), is(1.0D));
         assertThat(actualFailureSummary, scorecard.getHarnessRecoveryRate(), is(0.0D));
-        if (hasResourceHitExpectation(scenarios)) {
+        if (hasResourceHitExpectation(evaluatedSuite.scenarios())) {
             assertThat(actualFailureSummary, scorecard.getResourceHitRate(), is(1.0D));
         }
-        if (hasRecoveryExpectation(scenarios)) {
+        if (hasRecoveryExpectation(evaluatedSuite.scenarios())) {
             assertThat(actualFailureSummary, scorecard.getRecoveryRate(), is(1.0D));
         }
     }
@@ -257,7 +258,8 @@ final class LLMUsabilitySuiteRunner {
         return false;
     }
     
-    private String createFailureSummary(final LLMUsabilityScorecard scorecard) {
+    private String createFailureSummary(final EvaluatedSuite evaluatedSuite) {
+        LLMUsabilityScorecard scorecard = evaluatedSuite.scorecard();
         StringBuilder result = new StringBuilder("LLM usability suite did not meet the baseline.");
         result.append(" overallScore=").append(scorecard.getOverallScore());
         result.append(", fullScore=").append(scorecard.isFullScore());
@@ -268,16 +270,19 @@ final class LLMUsabilitySuiteRunner {
         result.append(", recoveryRate=").append(scorecard.getRecoveryRate());
         result.append(", nativeToolCallRate=").append(scorecard.getNativeToolCallRate());
         result.append(", harnessRecoveryRate=").append(scorecard.getHarnessRecoveryRate());
-        for (LLMUsabilityScenarioResult each : scorecard.getScenarioResults()) {
-            if (each.isSuccess()) {
+        for (EvaluatedScenario each : evaluatedSuite.evaluatedScenarios()) {
+            LLMUsabilityScenarioResult scenarioResult = each.scenarioResult();
+            if (scenarioResult.isSuccess()) {
                 continue;
             }
             result.append(" [");
-            result.append(each.getScenarioId());
+            result.append(scenarioResult.getScenarioId());
             result.append(": ");
-            result.append(each.getFailureType());
+            result.append(scenarioResult.getFailureType());
             result.append(" - ");
-            result.append(each.getMessage());
+            result.append(scenarioResult.getMessage());
+            result.append(", artifactDirectory=");
+            result.append(each.artifactDirectory());
             result.append(']');
         }
         return result.toString();
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunnerTest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunnerTest.java
index 35228845e7e..58309165b03 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunnerTest.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/suite/usability/LLMUsabilitySuiteRunnerTest.java
@@ -73,6 +73,18 @@ class LLMUsabilitySuiteRunnerTest {
         assertTrue(Files.isRegularFile(tempDir.resolve("run-id").resolve("core-suite").resolve("scorecard.json")));
     }
     
+    @Test
+    void assertFailureSummaryIncludesArtifactDirectory() {
+        LLME2EConfiguration configuration = createConfiguration();
+        AssertionError actual = assertThrows(AssertionError.class,
+                () -> new LLMUsabilitySuiteRunner().assertCoreSuite("core-suite", () -> List.of(createScenario(LLMUsabilityScenario.NATURAL_TASK_TAG)),
+                        scenario -> createConversationResult(configuration, scenario, LLME2EAssertionReport.failure("answer_mismatch", "Wrong answer.")),
+                        configuration));
+        Path artifactDirectory = tempDir.resolve("run-id").resolve("scenario-" + LLMUsabilityScenario.NATURAL_TASK_TAG);
+        assertTrue(actual.getMessage().contains("answer_mismatch - Wrong answer."));
+        assertTrue(actual.getMessage().contains("artifactDirectory=" + artifactDirectory));
+    }
+    
     private LLMConversationExecutor.ConversationResult createConversationResult(final LLME2EConfiguration configuration, final LLME2EScenario scenario) throws IOException {
         return createConversationResult(configuration, scenario, LLME2EAssertionReport.isSuccess("ok"));
     }