Skip to content

Commit 1f18087

Browse files
committed
refactor(mcp): reorganize annotation customizers and improve client ID matching
- Move McpAsyncAnnotationCustomizer and McpSyncAnnotationCustomizer to annotations package - Simplify ClientAnnotationScannerProperties by removing unused package filtering - Change client ID matching logic to require explicit case-insensitive match - Update imports and test annotations to specify explicit client IDs - Bump mcp-annotations version to 0.3.0-SNAPSHOT The client ID matching now requires an explicit match rather than allowing empty/null client IDs to match all clients, providing more precise control over which customizers apply to which clients. Signed-off-by: Christian Tzolov <[email protected]>
1 parent 1ce514b commit 1f18087

File tree

7 files changed

+20
-42
lines changed

7 files changed

+20
-42
lines changed

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/main/java/org/springframework/ai/mcp/client/common/autoconfigure/McpClientAutoConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import org.springaicommunity.mcp.method.progress.SyncProgressSpecification;
3333
import org.springaicommunity.mcp.method.sampling.AsyncSamplingSpecification;
3434
import org.springaicommunity.mcp.method.sampling.SyncSamplingSpecification;
35+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpAsyncAnnotationCustomizer;
36+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpSyncAnnotationCustomizer;
3537
import org.springframework.ai.mcp.client.common.autoconfigure.configurer.McpAsyncClientConfigurer;
3638
import org.springframework.ai.mcp.client.common.autoconfigure.configurer.McpSyncClientConfigurer;
3739
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties;

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/main/java/org/springframework/ai/mcp/client/common/autoconfigure/annotations/ClientAnnotationScannerProperties.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616

1717
package org.springframework.ai.mcp.client.common.autoconfigure.annotations;
1818

19-
import java.util.HashSet;
20-
import java.util.Set;
21-
2219
import org.springframework.boot.context.properties.ConfigurationProperties;
2320

2421
/**
@@ -31,32 +28,12 @@ public class ClientAnnotationScannerProperties {
3128

3229
private boolean enabled = true;
3330

34-
private Set<String> includePackages = new HashSet<>();
35-
36-
private Set<String> excludePackages = new HashSet<>();
37-
3831
public boolean isEnabled() {
3932
return enabled;
4033
}
4134

42-
public Set<String> getIncludePackages() {
43-
return includePackages;
44-
}
45-
46-
public Set<String> getExcludePackages() {
47-
return excludePackages;
48-
}
49-
5035
public void setEnabled(boolean enabled) {
5136
this.enabled = enabled;
5237
}
5338

54-
public void setIncludePackages(Set<String> includePackages) {
55-
this.includePackages = includePackages;
56-
}
57-
58-
public void setExcludePackages(Set<String> excludePackages) {
59-
this.excludePackages = excludePackages;
60-
}
61-
6239
}
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.ai.mcp.client.common.autoconfigure;
17+
package org.springframework.ai.mcp.client.common.autoconfigure.annotations;
1818

1919
import java.util.List;
2020

@@ -24,7 +24,6 @@
2424
import org.springaicommunity.mcp.method.sampling.AsyncSamplingSpecification;
2525
import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer;
2626
import org.springframework.util.CollectionUtils;
27-
import org.springframework.util.StringUtils;
2827

2928
import io.modelcontextprotocol.client.McpClient.AsyncSpec;
3029

@@ -57,31 +56,31 @@ public void customize(String name, AsyncSpec clientSpec) {
5756

5857
if (!CollectionUtils.isEmpty(asyncElicitationSpecifications)) {
5958
this.asyncElicitationSpecifications.forEach(elicitationSpec -> {
60-
if (!StringUtils.hasText(elicitationSpec.clientId()) || elicitationSpec.clientId().equals(name)) {
59+
if (elicitationSpec.clientId().equalsIgnoreCase(name)) {
6160
clientSpec.elicitation(elicitationSpec.elicitationHandler());
6261
}
6362
});
6463
}
6564

6665
if (!CollectionUtils.isEmpty(asyncSamplingSpecifications)) {
6766
this.asyncSamplingSpecifications.forEach(samplingSpec -> {
68-
if (!StringUtils.hasText(samplingSpec.clientId()) || samplingSpec.clientId().equals(name)) {
67+
if (samplingSpec.clientId().equalsIgnoreCase(name)) {
6968
clientSpec.sampling(samplingSpec.samplingHandler());
7069
}
7170
});
7271
}
7372

7473
if (!CollectionUtils.isEmpty(asyncLoggingSpecifications)) {
7574
this.asyncLoggingSpecifications.forEach(loggingSpec -> {
76-
if (!StringUtils.hasText(loggingSpec.clientId()) || loggingSpec.clientId().equals(name)) {
75+
if (loggingSpec.clientId().equalsIgnoreCase(name)) {
7776
clientSpec.loggingConsumer(loggingSpec.loggingHandler());
7877
}
7978
});
8079
}
8180

8281
if (!CollectionUtils.isEmpty(asyncProgressSpecifications)) {
8382
this.asyncProgressSpecifications.forEach(progressSpec -> {
84-
if (!StringUtils.hasText(progressSpec.clientId()) || progressSpec.clientId().equals(name)) {
83+
if (progressSpec.clientId().equalsIgnoreCase(name)) {
8584
clientSpec.progressConsumer(progressSpec.progressHandler());
8685
}
8786
});
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.ai.mcp.client.common.autoconfigure;
17+
package org.springframework.ai.mcp.client.common.autoconfigure.annotations;
1818

1919
import java.util.List;
20+
import java.util.concurrent.ConcurrentHashMap;
2021

2122
import org.springaicommunity.mcp.method.elicitation.SyncElicitationSpecification;
2223
import org.springaicommunity.mcp.method.logging.SyncLoggingSpecification;
2324
import org.springaicommunity.mcp.method.progress.SyncProgressSpecification;
2425
import org.springaicommunity.mcp.method.sampling.SyncSamplingSpecification;
2526
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
2627
import org.springframework.util.CollectionUtils;
27-
import org.springframework.util.StringUtils;
2828

2929
import io.modelcontextprotocol.client.McpClient.SyncSpec;
3030

@@ -57,31 +57,31 @@ public void customize(String name, SyncSpec clientSpec) {
5757

5858
if (!CollectionUtils.isEmpty(syncElicitationSpecifications)) {
5959
this.syncElicitationSpecifications.forEach(elicitationSpec -> {
60-
if (!StringUtils.hasText(elicitationSpec.clientId()) || elicitationSpec.clientId().equals(name)) {
60+
if (elicitationSpec.clientId().equalsIgnoreCase(name)) {
6161
clientSpec.elicitation(elicitationSpec.elicitationHandler());
6262
}
6363
});
6464
}
6565

6666
if (!CollectionUtils.isEmpty(syncSamplingSpecifications)) {
6767
this.syncSamplingSpecifications.forEach(samplingSpec -> {
68-
if (!StringUtils.hasText(samplingSpec.clientId()) || samplingSpec.clientId().equals(name)) {
68+
if (samplingSpec.clientId().equalsIgnoreCase(name)) {
6969
clientSpec.sampling(samplingSpec.samplingHandler());
7070
}
7171
});
7272
}
7373

7474
if (!CollectionUtils.isEmpty(syncLoggingSpecifications)) {
7575
this.syncLoggingSpecifications.forEach(loggingSpec -> {
76-
if (!StringUtils.hasText(loggingSpec.clientId()) || loggingSpec.clientId().equals(name)) {
76+
if (loggingSpec.clientId().equalsIgnoreCase(name)) {
7777
clientSpec.loggingConsumer(loggingSpec.loggingHandler());
7878
}
7979
});
8080
}
8181

8282
if (!CollectionUtils.isEmpty(syncProgressSpecifications)) {
8383
this.syncProgressSpecifications.forEach(progressSpec -> {
84-
if (!StringUtils.hasText(progressSpec.clientId()) || progressSpec.clientId().equals(name)) {
84+
if (progressSpec.clientId().equalsIgnoreCase(name)) {
8585
clientSpec.progressConsumer(progressSpec.progressHandler());
8686
}
8787
});

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StreamableMcpAnnotationsIT.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,13 +429,13 @@ public void progressHandler(ProgressNotification progressNotification) {
429429
testContext.progressLatch.countDown();
430430
}
431431

432-
@McpLogging
432+
@McpLogging(clientId = "server1")
433433
public void loggingHandler(LoggingMessageNotification loggingMessage) {
434434
testContext.loggingNotificationRef.set(loggingMessage);
435435
logger.info("MCP LOGGING: [{}] {}", loggingMessage.level(), loggingMessage.data());
436436
}
437437

438-
@McpSampling
438+
@McpSampling(clientId = "server1")
439439
public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
440440
logger.info("MCP SAMPLING: {}", llmRequest);
441441

@@ -447,7 +447,7 @@ public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
447447
.build();
448448
}
449449

450-
@McpElicitation
450+
@McpElicitation(clientId = "server1")
451451
public ElicitResult elicitationHandler(McpSchema.ElicitRequest request) {
452452
logger.info("MCP ELICITATION: {}", request);
453453
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StreamableMcpAnnotationsManualIT.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,13 +448,13 @@ public void progressHandler(ProgressNotification progressNotification) {
448448
testContext.progressLatch.countDown();
449449
}
450450

451-
@McpLogging
451+
@McpLogging(clientId = "server1")
452452
public void loggingHandler(LoggingMessageNotification loggingMessage) {
453453
testContext.loggingNotificationRef.set(loggingMessage);
454454
logger.info("MCP LOGGING: [{}] {}", loggingMessage.level(), loggingMessage.data());
455455
}
456456

457-
@McpSampling
457+
@McpSampling(clientId = "server1")
458458
public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
459459
logger.info("MCP SAMPLING: {}", llmRequest);
460460

@@ -466,7 +466,7 @@ public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
466466
.build();
467467
}
468468

469-
@McpElicitation
469+
@McpElicitation(clientId = "server1")
470470
public ElicitResult elicitationHandler(McpSchema.ElicitRequest request) {
471471
logger.info("MCP ELICITATION: {}", request);
472472
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@
331331

332332
<!-- MCP-->
333333
<mcp.sdk.version>0.11.3</mcp.sdk.version>
334-
<mcp-annotations.version>0.2.0</mcp-annotations.version>
334+
<mcp-annotations.version>0.3.0-SNAPSHOT</mcp-annotations.version>
335335

336336
<!-- plugin versions -->
337337
<antlr.version>4.13.1</antlr.version>

0 commit comments

Comments
 (0)