|
4 | 4 |
|
5 | 5 | package io.modelcontextprotocol.client; |
6 | 6 |
|
| 7 | +import java.time.Duration; |
| 8 | +import java.util.ArrayList; |
| 9 | +import java.util.HashMap; |
| 10 | +import java.util.List; |
| 11 | +import java.util.Map; |
| 12 | +import java.util.function.Consumer; |
| 13 | +import java.util.function.Function; |
| 14 | +import java.util.function.Supplier; |
| 15 | + |
7 | 16 | import io.modelcontextprotocol.common.McpTransportContext; |
8 | 17 | import io.modelcontextprotocol.json.McpJsonDefaults; |
9 | 18 | import io.modelcontextprotocol.json.schema.JsonSchemaValidator; |
|
12 | 21 | import io.modelcontextprotocol.spec.McpSchema.ClientCapabilities; |
13 | 22 | import io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest; |
14 | 23 | import io.modelcontextprotocol.spec.McpSchema.CreateMessageResult; |
15 | | -import io.modelcontextprotocol.spec.McpSchema.ElicitRequest; |
| 24 | +import io.modelcontextprotocol.spec.McpSchema.ElicitFormRequest; |
16 | 25 | import io.modelcontextprotocol.spec.McpSchema.ElicitResult; |
| 26 | +import io.modelcontextprotocol.spec.McpSchema.ElicitUrlRequest; |
17 | 27 | import io.modelcontextprotocol.spec.McpSchema.Implementation; |
18 | 28 | import io.modelcontextprotocol.spec.McpSchema.Root; |
19 | 29 | import io.modelcontextprotocol.spec.McpTransport; |
20 | 30 | import io.modelcontextprotocol.util.Assert; |
21 | 31 | import reactor.core.publisher.Mono; |
22 | 32 |
|
23 | | -import java.time.Duration; |
24 | | -import java.util.ArrayList; |
25 | | -import java.util.HashMap; |
26 | | -import java.util.List; |
27 | | -import java.util.Map; |
28 | | -import java.util.function.Consumer; |
29 | | -import java.util.function.Function; |
30 | | -import java.util.function.Supplier; |
31 | | - |
32 | 33 | /** |
33 | 34 | * Factory class for creating Model Context Protocol (MCP) clients. MCP is a protocol that |
34 | 35 | * enables AI models to interact with external tools and resources through a standardized |
@@ -185,9 +186,13 @@ class SyncSpec { |
185 | 186 |
|
186 | 187 | private final List<Consumer<McpSchema.ProgressNotification>> progressConsumers = new ArrayList<>(); |
187 | 188 |
|
| 189 | + private final List<Consumer<McpSchema.ElicitationCompleteNotification>> elicitationCompleteConsumers = new ArrayList<>(); |
| 190 | + |
188 | 191 | private Function<CreateMessageRequest, CreateMessageResult> samplingHandler; |
189 | 192 |
|
190 | | - private Function<ElicitRequest, ElicitResult> elicitationHandler; |
| 193 | + private Function<ElicitFormRequest, ElicitResult> formElicitationHandler; |
| 194 | + |
| 195 | + private Function<ElicitUrlRequest, ElicitResult> urlElicitationHandler; |
191 | 196 |
|
192 | 197 | private Supplier<McpTransportContext> contextProvider = () -> McpTransportContext.EMPTY; |
193 | 198 |
|
@@ -314,9 +319,24 @@ public SyncSpec sampling(Function<CreateMessageRequest, CreateMessageResult> sam |
314 | 319 | * @return This builder instance for method chaining |
315 | 320 | * @throws IllegalArgumentException if elicitationHandler is null |
316 | 321 | */ |
317 | | - public SyncSpec elicitation(Function<ElicitRequest, ElicitResult> elicitationHandler) { |
| 322 | + public SyncSpec elicitation(Function<ElicitFormRequest, ElicitResult> elicitationHandler) { |
318 | 323 | Assert.notNull(elicitationHandler, "Elicitation handler must not be null"); |
319 | | - this.elicitationHandler = elicitationHandler; |
| 324 | + this.formElicitationHandler = elicitationHandler; |
| 325 | + return this; |
| 326 | + } |
| 327 | + |
| 328 | + /** |
| 329 | + * Sets a custom elicitation handler for processing URL-mode elicitation message |
| 330 | + * requests. The elicitation handler can modify or validate messages before they |
| 331 | + * are sent to the server, enabling custom processing logic. |
| 332 | + * @param elicitationHandler A function that processes elicitation requests and |
| 333 | + * returns results. Must not be null. |
| 334 | + * @return This builder instance for method chaining |
| 335 | + * @throws IllegalArgumentException if elicitationHandler is null |
| 336 | + */ |
| 337 | + public SyncSpec urlElicitation(Function<ElicitUrlRequest, ElicitResult> elicitationHandler) { |
| 338 | + Assert.notNull(elicitationHandler, "Elicitation handler must not be null"); |
| 339 | + this.urlElicitationHandler = elicitationHandler; |
320 | 340 | return this; |
321 | 341 | } |
322 | 342 |
|
@@ -439,6 +459,36 @@ public SyncSpec progressConsumers(List<Consumer<McpSchema.ProgressNotification>> |
439 | 459 | return this; |
440 | 460 | } |
441 | 461 |
|
| 462 | + /** |
| 463 | + * Adds a consumer to be notified by the server when an URL elicitation is |
| 464 | + * complete. |
| 465 | + * @param elicitationCompleteConsumer A consumer that receives elicitation |
| 466 | + * complete notifications. Must not be null. |
| 467 | + * @return This builder instance for method chaining |
| 468 | + * @throws IllegalArgumentException if elicitationCompleteConsumer is null |
| 469 | + */ |
| 470 | + public SyncSpec elicitationCompleteConsumer( |
| 471 | + Consumer<McpSchema.ElicitationCompleteNotification> elicitationCompleteConsumer) { |
| 472 | + Assert.notNull(elicitationCompleteConsumer, "Elicitation complete consumer must not be null"); |
| 473 | + this.elicitationCompleteConsumers.add(elicitationCompleteConsumer); |
| 474 | + return this; |
| 475 | + } |
| 476 | + |
| 477 | + /** |
| 478 | + * Adds multiple consumers to be notified by the server when an URL elicitation is |
| 479 | + * complete. |
| 480 | + * @param elicitationCompleteConsumers A list of consumers that receives |
| 481 | + * elicitation complete notifications. Must not be null. |
| 482 | + * @return This builder instance for method chaining |
| 483 | + * @throws IllegalArgumentException if elicitationCompleteConsumers is null |
| 484 | + */ |
| 485 | + public SyncSpec elicitationCompleteConsumers( |
| 486 | + List<Consumer<McpSchema.ElicitationCompleteNotification>> elicitationCompleteConsumers) { |
| 487 | + Assert.notNull(elicitationCompleteConsumers, "Elicitation complete consumers must not be null"); |
| 488 | + this.elicitationCompleteConsumers.addAll(elicitationCompleteConsumers); |
| 489 | + return this; |
| 490 | + } |
| 491 | + |
442 | 492 | /** |
443 | 493 | * Add a provider of {@link McpTransportContext}, providing a context before |
444 | 494 | * calling any client operation. This allows to extract thread-locals and hand |
@@ -502,8 +552,9 @@ public SyncSpec applyElicitationDefaults(boolean applyElicitationDefaults) { |
502 | 552 | public McpSyncClient build() { |
503 | 553 | McpClientFeatures.Sync syncFeatures = new McpClientFeatures.Sync(this.clientInfo, this.capabilities, |
504 | 554 | this.roots, this.toolsChangeConsumers, this.resourcesChangeConsumers, this.resourcesUpdateConsumers, |
505 | | - this.promptsChangeConsumers, this.loggingConsumers, this.progressConsumers, this.samplingHandler, |
506 | | - this.elicitationHandler, this.enableCallToolSchemaCaching, this.applyElicitationDefaults); |
| 555 | + this.promptsChangeConsumers, this.loggingConsumers, this.progressConsumers, |
| 556 | + this.elicitationCompleteConsumers, this.samplingHandler, this.formElicitationHandler, |
| 557 | + this.urlElicitationHandler, this.enableCallToolSchemaCaching, this.applyElicitationDefaults); |
507 | 558 |
|
508 | 559 | McpClientFeatures.Async asyncFeatures = McpClientFeatures.Async.fromSync(syncFeatures); |
509 | 560 |
|
@@ -556,9 +607,13 @@ class AsyncSpec { |
556 | 607 |
|
557 | 608 | private final List<Function<McpSchema.ProgressNotification, Mono<Void>>> progressConsumers = new ArrayList<>(); |
558 | 609 |
|
| 610 | + private final List<Function<McpSchema.ElicitationCompleteNotification, Mono<Void>>> elicitationCompleteConsumers = new ArrayList<>(); |
| 611 | + |
559 | 612 | private Function<CreateMessageRequest, Mono<CreateMessageResult>> samplingHandler; |
560 | 613 |
|
561 | | - private Function<ElicitRequest, Mono<ElicitResult>> elicitationHandler; |
| 614 | + private Function<ElicitFormRequest, Mono<ElicitResult>> formElicitationHandler; |
| 615 | + |
| 616 | + private Function<ElicitUrlRequest, Mono<ElicitResult>> urlElicitationHandler; |
562 | 617 |
|
563 | 618 | private JsonSchemaValidator jsonSchemaValidator; |
564 | 619 |
|
@@ -683,9 +738,24 @@ public AsyncSpec sampling(Function<CreateMessageRequest, Mono<CreateMessageResul |
683 | 738 | * @return This builder instance for method chaining |
684 | 739 | * @throws IllegalArgumentException if elicitationHandler is null |
685 | 740 | */ |
686 | | - public AsyncSpec elicitation(Function<ElicitRequest, Mono<ElicitResult>> elicitationHandler) { |
| 741 | + public AsyncSpec elicitation(Function<ElicitFormRequest, Mono<ElicitResult>> elicitationHandler) { |
| 742 | + Assert.notNull(elicitationHandler, "Elicitation handler must not be null"); |
| 743 | + this.formElicitationHandler = elicitationHandler; |
| 744 | + return this; |
| 745 | + } |
| 746 | + |
| 747 | + /** |
| 748 | + * Sets a custom elicitation handler for processing elicitation message requests. |
| 749 | + * The elicitation handler can modify or validate messages before they are sent to |
| 750 | + * the server, enabling custom processing logic. |
| 751 | + * @param elicitationHandler A function that processes elicitation requests and |
| 752 | + * returns results. Must not be null. |
| 753 | + * @return This builder instance for method chaining |
| 754 | + * @throws IllegalArgumentException if elicitationHandler is null |
| 755 | + */ |
| 756 | + public AsyncSpec urlElicitation(Function<ElicitUrlRequest, Mono<ElicitResult>> elicitationHandler) { |
687 | 757 | Assert.notNull(elicitationHandler, "Elicitation handler must not be null"); |
688 | | - this.elicitationHandler = elicitationHandler; |
| 758 | + this.urlElicitationHandler = elicitationHandler; |
689 | 759 | return this; |
690 | 760 | } |
691 | 761 |
|
@@ -812,6 +882,36 @@ public AsyncSpec progressConsumers( |
812 | 882 | return this; |
813 | 883 | } |
814 | 884 |
|
| 885 | + /** |
| 886 | + * Adds a consumer to be notified by the server when an URL elicitation is |
| 887 | + * complete. |
| 888 | + * @param elicitationCompleteConsumer A consumer that receives elicitation |
| 889 | + * complete notifications. Must not be null. |
| 890 | + * @return This builder instance for method chaining |
| 891 | + * @throws IllegalArgumentException if elicitationCompleteConsumer is null |
| 892 | + */ |
| 893 | + public AsyncSpec elicitationCompleteConsumer( |
| 894 | + Function<McpSchema.ElicitationCompleteNotification, Mono<Void>> elicitationCompleteConsumer) { |
| 895 | + Assert.notNull(elicitationCompleteConsumer, "Elicitation complete consumer must not be null"); |
| 896 | + this.elicitationCompleteConsumers.add(elicitationCompleteConsumer); |
| 897 | + return this; |
| 898 | + } |
| 899 | + |
| 900 | + /** |
| 901 | + * Adds multiple consumers to be notified by the server when an URL elicitation is |
| 902 | + * complete. |
| 903 | + * @param elicitationCompleteConsumers A list of consumers that receives |
| 904 | + * elicitation complete notifications. Must not be null. |
| 905 | + * @return This builder instance for method chaining |
| 906 | + * @throws IllegalArgumentException if elicitationCompleteConsumers is null |
| 907 | + */ |
| 908 | + public AsyncSpec elicitationCompleteConsumers( |
| 909 | + List<Function<McpSchema.ElicitationCompleteNotification, Mono<Void>>> elicitationCompleteConsumers) { |
| 910 | + Assert.notNull(elicitationCompleteConsumers, "Elicitation complete consumers must not be null"); |
| 911 | + this.elicitationCompleteConsumers.addAll(elicitationCompleteConsumers); |
| 912 | + return this; |
| 913 | + } |
| 914 | + |
815 | 915 | /** |
816 | 916 | * Sets the JSON schema validator to use for validating tool responses against |
817 | 917 | * output schemas. |
@@ -863,7 +963,8 @@ public McpAsyncClient build() { |
863 | 963 | new McpClientFeatures.Async(this.clientInfo, this.capabilities, this.roots, |
864 | 964 | this.toolsChangeConsumers, this.resourcesChangeConsumers, this.resourcesUpdateConsumers, |
865 | 965 | this.promptsChangeConsumers, this.loggingConsumers, this.progressConsumers, |
866 | | - this.samplingHandler, this.elicitationHandler, this.enableCallToolSchemaCaching, |
| 966 | + this.elicitationCompleteConsumers, this.samplingHandler, this.formElicitationHandler, |
| 967 | + this.urlElicitationHandler, this.enableCallToolSchemaCaching, |
867 | 968 | this.applyElicitationDefaults)); |
868 | 969 | } |
869 | 970 |
|
|
0 commit comments