Skip to content
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,9 @@
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.spec.McpSchema;
import org.springaicommunity.mcp.method.changed.prompt.AsyncPromptListChangedSpecification;
import org.springaicommunity.mcp.method.changed.prompt.SyncPromptListChangedSpecification;
import org.springaicommunity.mcp.method.changed.resource.AsyncResourceListChangedSpecification;
import org.springaicommunity.mcp.method.changed.resource.SyncResourceListChangedSpecification;
import org.springaicommunity.mcp.method.changed.tool.AsyncToolListChangedSpecification;
import org.springaicommunity.mcp.method.changed.tool.SyncToolListChangedSpecification;
import org.springaicommunity.mcp.method.elicitation.AsyncElicitationSpecification;
import org.springaicommunity.mcp.method.elicitation.SyncElicitationSpecification;
import org.springaicommunity.mcp.method.logging.AsyncLoggingSpecification;
import org.springaicommunity.mcp.method.logging.SyncLoggingSpecification;
import org.springaicommunity.mcp.method.progress.AsyncProgressSpecification;
import org.springaicommunity.mcp.method.progress.SyncProgressSpecification;
import org.springaicommunity.mcp.method.sampling.AsyncSamplingSpecification;
import org.springaicommunity.mcp.method.sampling.SyncSamplingSpecification;

import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpAsyncAnnotationCustomizer;
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpSyncAnnotationCustomizer;

import org.springframework.ai.mcp.annotation.spring.ClientMcpAsyncHandlersRegistry;
import org.springframework.ai.mcp.annotation.spring.ClientMcpSyncHandlersRegistry;
import org.springframework.ai.mcp.client.common.autoconfigure.configurer.McpAsyncClientConfigurer;
import org.springframework.ai.mcp.client.common.autoconfigure.configurer.McpSyncClientConfigurer;
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties;
Expand Down Expand Up @@ -161,7 +147,8 @@ private String connectedClientName(String clientName, String serverConnectionNam
matchIfMissing = true)
public List<McpSyncClient> mcpSyncClients(McpSyncClientConfigurer mcpSyncClientConfigurer,
McpClientCommonProperties commonProperties,
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider) {
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider,
ClientMcpSyncHandlersRegistry clientMcpSyncHandlersRegistry) {

List<McpSyncClient> mcpSyncClients = new ArrayList<>();

Expand All @@ -176,7 +163,22 @@ public List<McpSyncClient> mcpSyncClients(McpSyncClientConfigurer mcpSyncClientC

McpClient.SyncSpec spec = McpClient.sync(namedTransport.transport())
.clientInfo(clientInfo)
.requestTimeout(commonProperties.getRequestTimeout());
.requestTimeout(commonProperties.getRequestTimeout())
.sampling(samplingRequest -> clientMcpSyncHandlersRegistry.handleSampling(namedTransport.name(),
samplingRequest))
.elicitation(elicitationRequest -> clientMcpSyncHandlersRegistry
.handleElicitation(namedTransport.name(), elicitationRequest))
.loggingConsumer(loggingMessageNotification -> clientMcpSyncHandlersRegistry
.handleLogging(namedTransport.name(), loggingMessageNotification))
.progressConsumer(progressNotification -> clientMcpSyncHandlersRegistry
.handleProgress(namedTransport.name(), progressNotification))
.toolsChangeConsumer(newTools -> clientMcpSyncHandlersRegistry
.handleToolListChanged(namedTransport.name(), newTools))
.promptsChangeConsumer(newPrompts -> clientMcpSyncHandlersRegistry
.handlePromptListChanged(namedTransport.name(), newPrompts))
.resourcesChangeConsumer(newResources -> clientMcpSyncHandlersRegistry
.handleResourceListChanged(namedTransport.name(), newResources))
.capabilities(clientMcpSyncHandlersRegistry.getCapabilities(namedTransport.name()));

spec = mcpSyncClientConfigurer.configure(namedTransport.name(), spec);

Expand Down Expand Up @@ -222,27 +224,14 @@ McpSyncClientConfigurer mcpSyncClientConfigurer(ObjectProvider<McpSyncClientCust
return new McpSyncClientConfigurer(customizerProvider.orderedStream().toList());
}

@Bean
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
matchIfMissing = true)
public McpSyncClientCustomizer mcpAnnotationMcpSyncClientCustomizer(List<SyncLoggingSpecification> loggingSpecs,
List<SyncSamplingSpecification> samplingSpecs, List<SyncElicitationSpecification> elicitationSpecs,
List<SyncProgressSpecification> progressSpecs,
List<SyncToolListChangedSpecification> syncToolListChangedSpecifications,
List<SyncResourceListChangedSpecification> syncResourceListChangedSpecifications,
List<SyncPromptListChangedSpecification> syncPromptListChangedSpecifications) {
return new McpSyncAnnotationCustomizer(samplingSpecs, loggingSpecs, elicitationSpecs, progressSpecs,
syncToolListChangedSpecifications, syncResourceListChangedSpecifications,
syncPromptListChangedSpecifications);
}

// Async client configuration

@Bean
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncClientConfigurer,
McpClientCommonProperties commonProperties,
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider) {
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider,
ClientMcpAsyncHandlersRegistry clientMcpAsyncHandlersRegistry) {

List<McpAsyncClient> mcpAsyncClients = new ArrayList<>();

Expand All @@ -257,7 +246,22 @@ public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncCli

McpClient.AsyncSpec spec = McpClient.async(namedTransport.transport())
.clientInfo(clientInfo)
.requestTimeout(commonProperties.getRequestTimeout());
.requestTimeout(commonProperties.getRequestTimeout())
.sampling(samplingRequest -> clientMcpAsyncHandlersRegistry.handleSampling(namedTransport.name(),
samplingRequest))
.elicitation(elicitationRequest -> clientMcpAsyncHandlersRegistry
.handleElicitation(namedTransport.name(), elicitationRequest))
.loggingConsumer(loggingMessageNotification -> clientMcpAsyncHandlersRegistry
.handleLogging(namedTransport.name(), loggingMessageNotification))
.progressConsumer(progressNotification -> clientMcpAsyncHandlersRegistry
.handleProgress(namedTransport.name(), progressNotification))
.toolsChangeConsumer(newTools -> clientMcpAsyncHandlersRegistry
.handleToolListChanged(namedTransport.name(), newTools))
.promptsChangeConsumer(newPrompts -> clientMcpAsyncHandlersRegistry
.handlePromptListChanged(namedTransport.name(), newPrompts))
.resourcesChangeConsumer(newResources -> clientMcpAsyncHandlersRegistry
.handleResourceListChanged(namedTransport.name(), newResources))
.capabilities(clientMcpAsyncHandlersRegistry.getCapabilities(namedTransport.name()));

spec = mcpAsyncClientConfigurer.configure(namedTransport.name(), spec);

Expand Down Expand Up @@ -287,18 +291,6 @@ McpAsyncClientConfigurer mcpAsyncClientConfigurer(ObjectProvider<McpAsyncClientC
return new McpAsyncClientConfigurer(customizerProvider.orderedStream().toList());
}

@Bean
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
public McpAsyncClientCustomizer mcpAnnotationMcpAsyncClientCustomizer(List<AsyncLoggingSpecification> loggingSpecs,
List<AsyncSamplingSpecification> samplingSpecs, List<AsyncElicitationSpecification> elicitationSpecs,
List<AsyncProgressSpecification> progressSpecs,
List<AsyncToolListChangedSpecification> toolListChangedSpecs,
List<AsyncResourceListChangedSpecification> resourceListChangedSpecs,
List<AsyncPromptListChangedSpecification> promptListChangedSpecs) {
return new McpAsyncAnnotationCustomizer(samplingSpecs, loggingSpecs, elicitationSpecs, progressSpecs,
toolListChangedSpecs, resourceListChangedSpecs, promptListChangedSpecs);
}

/**
* Record class that implements {@link AutoCloseable} to ensure proper cleanup of MCP
* clients.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
import org.springaicommunity.mcp.annotation.McpSampling;
import org.springaicommunity.mcp.annotation.McpToolListChanged;

import org.springframework.ai.mcp.annotation.spring.ClientMcpAsyncHandlersRegistry;
import org.springframework.ai.mcp.annotation.spring.ClientMcpSyncHandlersRegistry;
import org.springframework.ai.mcp.annotation.spring.scan.AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor;
import org.springframework.ai.mcp.annotation.spring.scan.AbstractAnnotatedMethodBeanPostProcessor;
import org.springframework.ai.mcp.annotation.spring.scan.AbstractMcpAnnotatedBeans;
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
Expand Down Expand Up @@ -60,15 +62,17 @@ public class McpClientAnnotationScannerAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public ClientMcpAnnotatedBeans clientAnnotatedBeans() {
return new ClientMcpAnnotatedBeans();
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
matchIfMissing = true)
public ClientMcpSyncHandlersRegistry clientMcpSyncHandlersRegistry() {
return new ClientMcpSyncHandlersRegistry();
}

@Bean
@ConditionalOnMissingBean
public static ClientAnnotatedMethodBeanPostProcessor clientAnnotatedMethodBeanPostProcessor(
ClientMcpAnnotatedBeans clientMcpAnnotatedBeans, McpClientAnnotationScannerProperties properties) {
return new ClientAnnotatedMethodBeanPostProcessor(clientMcpAnnotatedBeans, CLIENT_MCP_ANNOTATIONS);
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
public ClientMcpAsyncHandlersRegistry clientMcpAsyncHandlersRegistry() {
return new ClientMcpAsyncHandlersRegistry();
}

@Bean
Expand All @@ -90,15 +94,6 @@ public ClientAnnotatedBeanFactoryInitializationAotProcessor(

}

public static class ClientAnnotatedMethodBeanPostProcessor extends AbstractAnnotatedMethodBeanPostProcessor {

public ClientAnnotatedMethodBeanPostProcessor(ClientMcpAnnotatedBeans clientMcpAnnotatedBeans,
Set<Class<? extends Annotation>> targetAnnotations) {
super(clientMcpAnnotatedBeans, targetAnnotations);
}

}

static class AnnotationHints implements RuntimeHintsRegistrar {

@Override
Expand Down
Loading