@@ -92,6 +92,7 @@ The core module provides a set of annotations and callback implementations for p
92924 . ** Tool** - For implementing MCP tools with automatic JSON schema generation
93935 . ** Logging Consumer** - For handling logging message notifications
94946 . ** Sampling** - For handling sampling requests
95+ 7 . ** Elicitation** - For handling elicitation requests to gather additional information from users
9596
9697Each operation type has both synchronous and asynchronous implementations, allowing for flexible integration with different application architectures.
9798
@@ -110,6 +111,7 @@ The Spring integration module provides seamless integration with Spring AI and S
110111- ** ` @McpToolParam ` ** - Annotates tool method parameters with descriptions and requirement specifications
111112- ** ` @McpLoggingConsumer ` ** - Annotates methods that handle logging message notifications from MCP servers
112113- ** ` @McpSampling ` ** - Annotates methods that handle sampling requests from MCP servers
114+ - ** ` @McpElicitation ` ** - Annotates methods that handle elicitation requests to gather additional information from users
113115- ** ` @McpArg ` ** - Annotates method parameters as MCP arguments
114116
115117### Method Callbacks
@@ -145,6 +147,11 @@ The modules provide callback implementations for each operation type:
145147- ` SyncMcpSamplingMethodCallback ` - Synchronous implementation
146148- ` AsyncMcpSamplingMethodCallback ` - Asynchronous implementation using Reactor's Mono
147149
150+ #### Elicitation
151+ - ` AbstractMcpElicitationMethodCallback ` - Base class for elicitation method callbacks
152+ - ` SyncMcpElicitationMethodCallback ` - Synchronous implementation
153+ - ` AsyncMcpElicitationMethodCallback ` - Asynchronous implementation using Reactor's Mono
154+
148155### Providers
149156
150157The project includes provider classes that scan for annotated methods and create appropriate callbacks:
@@ -158,6 +165,8 @@ The project includes provider classes that scan for annotated methods and create
158165- ` AsyncMcpLoggingConsumerProvider ` - Processes ` @McpLoggingConsumer ` annotations for asynchronous operations
159166- ` SyncMcpSamplingProvider ` - Processes ` @McpSampling ` annotations for synchronous operations
160167- ` AsyncMcpSamplingProvider ` - Processes ` @McpSampling ` annotations for asynchronous operations
168+ - ` SyncMcpElicitationProvider ` - Processes ` @McpElicitation ` annotations for synchronous operations
169+ - ` AsyncMcpElicitationProvider ` - Processes ` @McpElicitation ` annotations for asynchronous operations
161170
162171### Spring Integration
163172
@@ -650,6 +659,128 @@ public class MyMcpClient {
650659}
651660```
652661
662+ ### Mcp Client Elicitation Example
663+
664+ ``` java
665+ public class ElicitationHandler {
666+
667+ /**
668+ * Handle elicitation requests with a synchronous implementation.
669+ * @param request The elicitation request
670+ * @return The elicitation result
671+ */
672+ @McpElicitation
673+ public ElicitResult handleElicitationRequest (ElicitRequest request ) {
674+ // Example implementation that accepts the request and returns user data
675+ // In a real implementation, this would present a form to the user
676+ // and collect their input based on the requested schema
677+
678+ Map<String , Object > userData = new HashMap<> ();
679+
680+ // Check what information is being requested based on the schema
681+ Map<String , Object > schema = request. requestedSchema();
682+ if (schema != null && schema. containsKey(" properties" )) {
683+ @SuppressWarnings (" unchecked" )
684+ Map<String , Object > properties = (Map<String , Object > ) schema. get(" properties" );
685+
686+ // Simulate user providing the requested information
687+ if (properties. containsKey(" name" )) {
688+ userData. put(" name" , " John Doe" );
689+ }
690+ if (properties. containsKey(" email" )) {
691+ userData. put(" email" , " john.doe@example.com" );
692+ }
693+ if (properties. containsKey(" age" )) {
694+ userData. put(" age" , 30 );
695+ }
696+ if (properties. containsKey(" preferences" )) {
697+ userData. put(" preferences" , Map . of(" theme" , " dark" , " notifications" , true ));
698+ }
699+ }
700+
701+ return new ElicitResult (ElicitResult . Action . ACCEPT , userData);
702+ }
703+
704+ /**
705+ * Handle elicitation requests that should be declined.
706+ * @param request The elicitation request
707+ * @return The elicitation result with decline action
708+ */
709+ @McpElicitation
710+ public ElicitResult handleDeclineElicitationRequest (ElicitRequest request ) {
711+ // Example of declining an elicitation request
712+ return new ElicitResult (ElicitResult . Action . DECLINE , null );
713+ }
714+ }
715+
716+ public class AsyncElicitationHandler {
717+
718+ /**
719+ * Handle elicitation requests with an asynchronous implementation.
720+ * @param request The elicitation request
721+ * @return A Mono containing the elicitation result
722+ */
723+ @McpElicitation
724+ public Mono<ElicitResult > handleAsyncElicitationRequest (ElicitRequest request ) {
725+ return Mono . fromCallable(() - > {
726+ // Simulate async processing of the elicitation request
727+ // In a real implementation, this might involve showing a UI form
728+ // and waiting for user input
729+
730+ Map<String , Object > userData = new HashMap<> ();
731+ userData. put(" response" , " Async elicitation response" );
732+ userData. put(" timestamp" , System . currentTimeMillis());
733+ userData. put(" message" , request. message());
734+
735+ return new ElicitResult (ElicitResult . Action . ACCEPT , userData);
736+ }). delayElement(Duration . ofMillis(100 )); // Simulate processing delay
737+ }
738+
739+ /**
740+ * Handle elicitation requests that might be cancelled.
741+ * @param request The elicitation request
742+ * @return A Mono containing the elicitation result with cancel action
743+ */
744+ @McpElicitation
745+ public Mono<ElicitResult > handleCancelElicitationRequest (ElicitRequest request ) {
746+ return Mono . just(new ElicitResult (ElicitResult . Action . CANCEL , null ));
747+ }
748+ }
749+
750+ public class MyMcpClient {
751+
752+ public static McpSyncClient createSyncClientWithElicitation (ElicitationHandler elicitationHandler ) {
753+ Function<ElicitRequest , ElicitResult > elicitationHandler =
754+ new SyncMcpElicitationProvider (List . of(elicitationHandler)). getElicitationHandler();
755+
756+ McpSyncClient client = McpClient . sync(transport)
757+ .capabilities(ClientCapabilities . builder()
758+ .elicitation() // Enable elicitation support
759+ // Other capabilities...
760+ .build())
761+ .elicitationHandler(elicitationHandler)
762+ .build();
763+
764+ return client;
765+ }
766+
767+ public static McpAsyncClient createAsyncClientWithElicitation (AsyncElicitationHandler asyncElicitationHandler ) {
768+ Function<ElicitRequest , Mono<ElicitResult > > elicitationHandler =
769+ new AsyncMcpElicitationProvider (List . of(asyncElicitationHandler)). getElicitationHandler();
770+
771+ McpAsyncClient client = McpClient . async(transport)
772+ .capabilities(ClientCapabilities . builder()
773+ .elicitation() // Enable elicitation support
774+ // Other capabilities...
775+ .build())
776+ .elicitationHandler(elicitationHandler)
777+ .build();
778+
779+ return client;
780+ }
781+ }
782+ ```
783+
653784
654785### Spring Integration Example
655786
@@ -704,6 +835,18 @@ public class McpConfig {
704835 List<AsyncSamplingHandler > asyncSamplingHandlers ) {
705836 return SpringAiMcpAnnotationProvider . createAsyncSamplingHandler(asyncSamplingHandlers);
706837 }
838+
839+ @Bean
840+ public Function<ElicitRequest , ElicitResult > syncElicitationHandler (
841+ List<ElicitationHandler > elicitationHandlers ) {
842+ return SpringAiMcpAnnotationProvider . createSyncElicitationHandler(elicitationHandlers);
843+ }
844+
845+ @Bean
846+ public Function<ElicitRequest , Mono<ElicitResult > > asyncElicitationHandler (
847+ List<AsyncElicitationHandler > asyncElicitationHandlers ) {
848+ return SpringAiMcpAnnotationProvider . createAsyncElicitationHandler(asyncElicitationHandlers);
849+ }
707850}
708851```
709852
0 commit comments