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;
+ }
}