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 eb9d330a332 Refactor MCPToolElicitationHandler (#38763)
eb9d330a332 is described below

commit eb9d330a332091c2a5c5758f6c1cc5e80d1a0465
Author: Liang Zhang <[email protected]>
AuthorDate: Sun May 31 12:07:01 2026 +0800

    Refactor MCPToolElicitationHandler (#38763)
    
    * Refactor MCPToolElicitationHandler
    
    * Refactor MCPToolElicitationHandler
    
    * Refactor MCPToolElicitationHandler
    
    * Refactor MCPToolElicitationHandler
    
    * Refactor MCPToolElicitationHandler
    
    * Refactor MCPToolElicitationHandler
---
 .../tool/MCPClientElicitationCapabilities.java     |  2 +-
 .../tool/MCPToolClarificationPolicy.java           | 12 ++--
 .../MCPToolElicitationFallbackResponseFactory.java |  3 +-
 .../capability/tool/MCPToolElicitationHandler.java | 82 +++++++++-------------
 .../tool/MCPToolSpecificationFactory.java          | 10 +--
 5 files changed, 49 insertions(+), 60 deletions(-)

diff --git 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPClientElicitationCapabilities.java
 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPClientElicitationCapabilities.java
index eebdc80d6b3..a482011de16 100644
--- 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPClientElicitationCapabilities.java
+++ 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPClientElicitationCapabilities.java
@@ -26,8 +26,8 @@ import lombok.RequiredArgsConstructor;
 /**
  * MCP client elicitation capabilities.
  */
-@Getter
 @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+@Getter
 public final class MCPClientElicitationCapabilities {
     
     private final boolean formModeSupported;
diff --git 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
index 370816fd287..0cfed9778bf 100644
--- 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
+++ 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolClarificationPolicy.java
@@ -52,14 +52,14 @@ final class MCPToolClarificationPolicy {
     private static final List<String> SENSITIVE_FIELD_NAME_MARKERS = List.of(
             "password", "passwd", "passphrase", "secret", "token", 
"accesstoken", "apikey", "privatekey", "credential", "card", "cvv", "payment", 
"key");
     
-    boolean requiresPlanningClarification(final MCPToolDescriptor 
toolDescriptor, final Map<String, Object> payload) {
+    boolean requiresPlanningClarification(final MCPToolDescriptor descriptor, 
final Map<String, Object> payload) {
         Object clarificationQuestions = 
payload.get(MCPPayloadFieldNames.CLARIFICATION_QUESTIONS);
-        return 
MCPDescriptorCatalogIndex.findToolRuntimeDescriptor(toolDescriptor.getName())
+        return 
MCPDescriptorCatalogIndex.findToolRuntimeDescriptor(descriptor.getName())
                 .map(optional -> 
PLANNING_WORKFLOW_ROLE.equals(optional.getWorkflowRole())).orElse(false)
                 && clarificationQuestions instanceof List<?> questions && 
!questions.isEmpty();
     }
     
-    Optional<ClarificationForm> createClarificationForm(final Map<String, 
Object> payload, final MCPToolDescriptor toolDescriptor) {
+    Optional<ClarificationForm> createClarificationForm(final Map<String, 
Object> payload, final MCPToolDescriptor descriptor) {
         String planId = getPlanId(payload).trim();
         if (planId.isEmpty()) {
             return Optional.empty();
@@ -76,7 +76,7 @@ final class MCPToolClarificationPolicy {
             if (!(each instanceof Map<?, ?> question) || 
isSensitiveClarificationQuestion(question)) {
                 return Optional.empty();
             }
-            Optional<ArgumentBinding> binding = 
createArgumentBinding(question, toolDescriptor, questionIndex);
+            Optional<ArgumentBinding> binding = 
createArgumentBinding(question, descriptor, questionIndex);
             if (binding.isEmpty()) {
                 return Optional.empty();
             }
@@ -102,13 +102,13 @@ final class MCPToolClarificationPolicy {
         return false;
     }
     
-    private Optional<ArgumentBinding> createArgumentBinding(final Map<?, ?> 
question, final MCPToolDescriptor toolDescriptor, final int questionIndex) {
+    private Optional<ArgumentBinding> createArgumentBinding(final Map<?, ?> 
question, final MCPToolDescriptor descriptor, final int questionIndex) {
         String field = getField(question);
         if (field.isEmpty()) {
             return Optional.empty();
         }
         String formPropertyName = FORM_PROPERTY_PREFIX + questionIndex;
-        return findArgumentBinding(field, toolDescriptor, formPropertyName, 
getInputType(question), getAllowedValues(question));
+        return findArgumentBinding(field, descriptor, formPropertyName, 
getInputType(question), getAllowedValues(question));
     }
     
     private boolean isSensitiveClarificationQuestion(final Map<?, ?> question) 
{
diff --git 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactory.java
 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactory.java
index 46b8d3f0412..da99b452d62 100644
--- 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactory.java
+++ 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationFallbackResponseFactory.java
@@ -52,8 +52,7 @@ public final class MCPToolElicitationFallbackResponseFactory {
      * @param clientCapabilities client elicitation capabilities
      * @return MCP response
      */
-    public MCPResponse create(final Map<String, Object> payload, final 
MCPToolElicitationFallbackReason fallbackReason,
-                              final MCPClientElicitationCapabilities 
clientCapabilities) {
+    public MCPResponse create(final Map<String, Object> payload, final 
MCPToolElicitationFallbackReason fallbackReason, final 
MCPClientElicitationCapabilities clientCapabilities) {
         Map<String, Object> result = new LinkedHashMap<>(payload);
         if (clarificationPolicy.hasSensitiveClarificationQuestions(payload)) {
             result.put(MCPPayloadFieldNames.CLARIFICATION_QUESTIONS, 
createSanitizedClarificationQuestions(payload));
diff --git 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationHandler.java
 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationHandler.java
index 14d6c031041..5b8748a839e 100644
--- 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationHandler.java
+++ 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolElicitationHandler.java
@@ -56,60 +56,32 @@ final class MCPToolElicitationHandler {
     
     private final MCPToolElicitationFallbackResponseFactory 
fallbackResponseFactory = new MCPToolElicitationFallbackResponseFactory();
     
-    boolean shouldHandle(final MCPToolDescriptor toolDescriptor, final 
Map<String, Object> payload) {
-        return 
clarificationPolicy.requiresPlanningClarification(toolDescriptor, payload);
+    boolean shouldHandle(final MCPToolDescriptor descriptor, final Map<String, 
Object> payload) {
+        return clarificationPolicy.requiresPlanningClarification(descriptor, 
payload);
     }
     
-    MCPResponse handle(final McpSyncServerExchange exchange, final 
MCPToolDefinition toolDefinition, final Map<String, Object> arguments,
-                       final MCPResponse fallbackResponse, final Map<String, 
Object> payload) {
-        MCPToolDescriptor toolDescriptor = toolDefinition.getDescriptor();
+    Optional<MCPResponse> handle(final McpSyncServerExchange exchange, final 
MCPToolDefinition definition, final Map<String, Object> arguments, final 
Map<String, Object> payload) {
         MCPClientElicitationCapabilities clientCapabilities = 
MCPClientElicitationCapabilities.from(exchange);
-        Optional<MCPToolClarificationPolicy.ClarificationForm> 
clarificationForm = clarificationPolicy.createClarificationForm(payload, 
toolDescriptor);
+        Optional<MCPToolClarificationPolicy.ClarificationForm> 
clarificationForm = clarificationPolicy.createClarificationForm(payload, 
definition.getDescriptor());
         if (clarificationForm.isEmpty()) {
-            return createFallbackResponse(payload, 
getUnavailableFormFallbackReason(payload, clientCapabilities), 
clientCapabilities);
+            return Optional.of(fallbackResponseFactory.create(payload, 
getUnavailableFormFallbackReason(payload, clientCapabilities), 
clientCapabilities));
         }
         if (!clientCapabilities.isFormModeSupported()) {
-            return createFallbackResponse(payload, 
MCPToolElicitationFallbackReason.CLIENT_UNSUPPORTED, clientCapabilities);
+            return Optional.of(fallbackResponseFactory.create(payload, 
MCPToolElicitationFallbackReason.CLIENT_UNSUPPORTED, clientCapabilities));
         }
         if (!STDIO_TRANSPORT.equals(activeTransport)) {
-            return createFallbackResponse(payload, 
MCPToolElicitationFallbackReason.REMOTE_IDENTITY_REQUIRED, clientCapabilities);
+            return Optional.of(fallbackResponseFactory.create(payload, 
MCPToolElicitationFallbackReason.REMOTE_IDENTITY_REQUIRED, clientCapabilities));
         }
-        FormContinuationContext continuationContext = 
createContinuationContext(exchange, toolDescriptor, arguments, 
clarificationForm.get());
+        FormContinuationContext continuationContext = new 
FormContinuationContext(
+                definition.getDescriptor().getName(), exchange.sessionId(), 
clarificationForm.get().planId(), arguments.hashCode(), 
clock.instant().plus(FORM_CONTINUATION_TTL),
+                UUID.randomUUID().toString());
         McpSchema.ElicitResult elicitedResult;
         try {
-            elicitedResult = 
exchange.createElicitation(createElicitRequest(toolDescriptor.getName(), 
clarificationForm.get(), continuationContext.formRequestId()));
+            elicitedResult = 
exchange.createElicitation(createElicitRequest(definition.getDescriptor().getName(),
 clarificationForm.get(), continuationContext.formRequestId()));
         } catch (final McpError | IllegalStateException | 
UnsupportedOperationException ignored) {
-            return createFallbackResponse(payload, 
MCPToolElicitationFallbackReason.ELICITATION_FAILED, clientCapabilities);
-        }
-        return continueOrFallback(exchange, toolDefinition, arguments, 
fallbackResponse, payload, clarificationForm.get(), continuationContext, 
elicitedResult, clientCapabilities);
-    }
-    
-    private MCPResponse continueOrFallback(final McpSyncServerExchange 
exchange, final MCPToolDefinition toolDefinition, final Map<String, Object> 
arguments,
-                                           final MCPResponse fallbackResponse, 
final Map<String, Object> payload,
-                                           final 
MCPToolClarificationPolicy.ClarificationForm clarificationForm,
-                                           final FormContinuationContext 
continuationContext, final McpSchema.ElicitResult elicitedResult,
-                                           final 
MCPClientElicitationCapabilities clientCapabilities) {
-        if (null == elicitedResult || null == elicitedResult.action()) {
-            return createFallbackResponse(payload, 
MCPToolElicitationFallbackReason.MALFORMED_ELICITATION_RESULT, 
clientCapabilities);
-        }
-        if (McpSchema.ElicitResult.Action.ACCEPT != elicitedResult.action()) {
-            return fallbackResponse;
+            return Optional.of(fallbackResponseFactory.create(payload, 
MCPToolElicitationFallbackReason.ELICITATION_FAILED, clientCapabilities));
         }
-        if (null == elicitedResult.content()) {
-            return createFallbackResponse(payload, 
MCPToolElicitationFallbackReason.MALFORMED_ELICITATION_RESULT, 
clientCapabilities);
-        }
-        if (!continuationContext.isActive(activeTransport, clock, exchange, 
toolDefinition.getDescriptor(), arguments, clarificationForm)) {
-            return createFallbackResponse(payload, 
MCPToolElicitationFallbackReason.STALE_ELICITATION, clientCapabilities);
-        }
-        if (!clarificationPolicy.isValidElicitedContent(clarificationForm, 
elicitedResult.content())) {
-            return createFallbackResponse(payload, 
MCPToolElicitationFallbackReason.INVALID_ELICITED_CONTENT, clientCapabilities);
-        }
-        return toolController.handle(exchange.sessionId(), toolDefinition, 
clarificationPolicy.mergeArguments(arguments, clarificationForm, 
elicitedResult.content()));
-    }
-    
-    private MCPResponse createFallbackResponse(final Map<String, Object> 
payload, final MCPToolElicitationFallbackReason fallbackReason,
-                                               final 
MCPClientElicitationCapabilities clientCapabilities) {
-        return fallbackResponseFactory.create(payload, fallbackReason, 
clientCapabilities);
+        return continueOrFallback(exchange, definition, arguments, payload, 
clarificationForm.get(), continuationContext, elicitedResult, 
clientCapabilities);
     }
     
     private MCPToolElicitationFallbackReason 
getUnavailableFormFallbackReason(final Map<String, Object> payload, final 
MCPClientElicitationCapabilities clientCapabilities) {
@@ -121,12 +93,6 @@ final class MCPToolElicitationHandler {
                 : MCPToolElicitationFallbackReason.AMBIGUOUS_FIELD_BINDING;
     }
     
-    private FormContinuationContext createContinuationContext(final 
McpSyncServerExchange exchange, final MCPToolDescriptor toolDescriptor, final 
Map<String, Object> arguments,
-                                                              final 
MCPToolClarificationPolicy.ClarificationForm clarificationForm) {
-        return new FormContinuationContext(toolDescriptor.getName(), 
exchange.sessionId(), clarificationForm.planId(), arguments.hashCode(), 
clock.instant().plus(FORM_CONTINUATION_TTL),
-                UUID.randomUUID().toString());
-    }
-    
     private McpSchema.ElicitRequest createElicitRequest(final String toolName, 
final MCPToolClarificationPolicy.ClarificationForm clarificationForm, final 
String formRequestId) {
         return McpSchema.ElicitRequest.builder()
                 .message(String.format("Provide missing ShardingSphere 
workflow inputs for `%s`.", toolName))
@@ -142,6 +108,28 @@ final class MCPToolElicitationHandler {
                 MCPShardingSphereMetadataKeys.FORM_REQUEST_ID, formRequestId);
     }
     
+    private Optional<MCPResponse> continueOrFallback(final 
McpSyncServerExchange exchange, final MCPToolDefinition toolDefinition, final 
Map<String, Object> arguments,
+                                                     final Map<String, Object> 
payload, final MCPToolClarificationPolicy.ClarificationForm clarificationForm,
+                                                     final 
FormContinuationContext continuationContext, final McpSchema.ElicitResult 
elicitedResult,
+                                                     final 
MCPClientElicitationCapabilities clientCapabilities) {
+        if (null == elicitedResult || null == elicitedResult.action()) {
+            return Optional.of(fallbackResponseFactory.create(payload, 
MCPToolElicitationFallbackReason.MALFORMED_ELICITATION_RESULT, 
clientCapabilities));
+        }
+        if (McpSchema.ElicitResult.Action.ACCEPT != elicitedResult.action()) {
+            return Optional.empty();
+        }
+        if (null == elicitedResult.content()) {
+            return Optional.of(fallbackResponseFactory.create(payload, 
MCPToolElicitationFallbackReason.MALFORMED_ELICITATION_RESULT, 
clientCapabilities));
+        }
+        if (!continuationContext.isActive(activeTransport, clock, exchange, 
toolDefinition.getDescriptor(), arguments, clarificationForm)) {
+            return Optional.of(fallbackResponseFactory.create(payload, 
MCPToolElicitationFallbackReason.STALE_ELICITATION, clientCapabilities));
+        }
+        if (!clarificationPolicy.isValidElicitedContent(clarificationForm, 
elicitedResult.content())) {
+            return Optional.of(fallbackResponseFactory.create(payload, 
MCPToolElicitationFallbackReason.INVALID_ELICITED_CONTENT, clientCapabilities));
+        }
+        return Optional.of(toolController.handle(exchange.sessionId(), 
toolDefinition, clarificationPolicy.mergeArguments(arguments, 
clarificationForm, elicitedResult.content())));
+    }
+    
     private record FormContinuationContext(String toolName, String sessionId, 
String planId, int argumentsHashCode, Instant expiresAt, String formRequestId) {
 
         private boolean isActive(final String activeTransport, final Clock 
clock, final McpSyncServerExchange exchange, final MCPToolDescriptor 
toolDescriptor,
diff --git 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolSpecificationFactory.java
 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolSpecificationFactory.java
index b80016f152e..cefa7b13d77 100644
--- 
a/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolSpecificationFactory.java
+++ 
b/mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/capability/tool/MCPToolSpecificationFactory.java
@@ -95,12 +95,14 @@ public final class MCPToolSpecificationFactory {
             Map<String, Object> arguments = 
Optional.ofNullable(request.arguments()).orElse(Collections.emptyMap());
             MCPToolDefinition definition = 
ToolDefinitionRegistry.getToolDefinition(request.name());
             MCPResponse response = controller.handle(exchange.sessionId(), 
definition, arguments);
-            Map<String, Object> payload = response.toPayload();
-            return elicitationHandler.shouldHandle(definition.getDescriptor(), 
payload)
-                    ? callToolResultFactory.create(definition.getDescriptor(), 
elicitationHandler.handle(exchange, definition, arguments, response, payload))
-                    : callToolResultFactory.create(definition.getDescriptor(), 
response);
+            return callToolResultFactory.create(definition.getDescriptor(), 
getMcpResponse(exchange, response, definition, arguments));
         } catch (final UnsupportedToolException ignored) {
             throw MCPTransportErrorFactory.createError(new 
UnsupportedToolException(request.name()));
         }
     }
+    
+    private MCPResponse getMcpResponse(final McpSyncServerExchange exchange, 
final MCPResponse response, final MCPToolDefinition definition, final 
Map<String, Object> arguments) {
+        Map<String, Object> payload = response.toPayload();
+        return elicitationHandler.shouldHandle(definition.getDescriptor(), 
payload) ? elicitationHandler.handle(exchange, definition, arguments, 
payload).orElse(response) : response;
+    }
 }

Reply via email to