Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@

package com.alibaba.cloud.ai.autoconfigure.mcp.discovery.client;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

import static com.alibaba.cloud.ai.mcp.nacos.NacosMcpProperties.DEFAULT_ADDRESS;
import com.alibaba.cloud.ai.mcp.nacos.NacosMcpClientProperties;
import com.alibaba.cloud.ai.mcp.nacos.service.NacosMcpOperationService;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.utils.StringUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

import static com.alibaba.cloud.ai.mcp.nacos.NacosMcpProperties.DEFAULT_ADDRESS;

/**
* @author yingzi
* @since 2025/6/4 19:16
Expand All @@ -41,7 +41,7 @@
public class NacosMcpAutoConfiguration {

@Bean
public Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap(NacosMcpClientProperties nacosMcpClientProperties) {
public Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap(NacosMcpClientProperties nacosMcpClientProperties, ObjectProvider<NacosMcpOperationService> registryServiceProvider) {
Map<String, NacosMcpOperationService> map = new HashMap<>();
nacosMcpClientProperties.getConfigs().forEach((name, nacosSseParameters) -> {
Properties properties = new Properties();
Expand All @@ -60,19 +60,19 @@ public Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap(NacosMc
else {
properties.put(PropertyKeyConst.ENDPOINT, endpoint);
}

if (StringUtils.isEmpty(nacosSseParameters.serverAddr()) && StringUtils.isEmpty(nacosSseParameters.endpoint())) {
properties.put(PropertyKeyConst.SERVER_ADDR, DEFAULT_ADDRESS);
}

try {
NacosMcpOperationService nacosMcpOperationService = new NacosMcpOperationService(properties);
map.put(name, nacosMcpOperationService);
} catch (NacosException e) {
throw new RuntimeException(e);
}
});

registryServiceProvider.ifAvailable(service -> {
map.put("nacosMcpOperationService", service);
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded key "nacosMcpOperationService" will not match the connection names used in client configurations. When client configurations call nacosMcpOperationServiceMap.get(name) (where name comes from getConnections()), it will return null if the connection name is not "nacosMcpOperationService".

Consider either:

  1. Using a well-known constant key and documenting that connection configs should use this key when a registry service is present
  2. Adding the registry service to all configured connection names
  3. Implementing a fallback mechanism in the client configurations to use the registry service when a connection-specific service is not found
Suggested change
map.put("nacosMcpOperationService", service);
map.put("nacosMcpOperationService", service);
// Add registry service to all connection names as fallback
nacosMcpClientProperties.getConfigs().forEach((name, nacosSseParameters) -> {
if (!map.containsKey(name)) {
map.put(name, service);
}
});

Copilot uses AI. Check for mistakes.
});
return map;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,28 @@

package com.alibaba.cloud.ai.autoconfigure.mcp.discovery.client;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.alibaba.cloud.ai.mcp.discovery.client.transport.DistributedAsyncMcpClient;
import com.alibaba.cloud.ai.mcp.discovery.client.transport.DistributedSyncMcpClient;
import com.alibaba.cloud.ai.mcp.discovery.client.transport.sse.SseWebFluxDistributedAsyncMcpClient;
import com.alibaba.cloud.ai.mcp.discovery.client.transport.sse.SseWebFluxDistributedSyncMcpClient;
import com.alibaba.cloud.ai.mcp.nacos.NacosMcpClientProperties;
import com.alibaba.cloud.ai.mcp.nacos.service.NacosMcpOperationService;
import com.alibaba.cloud.ai.mcp.nacos.NacosMcpSseClientProperties;
import org.springframework.beans.factory.ObjectProvider;
import com.alibaba.cloud.ai.mcp.nacos.service.NacosMcpOperationService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
* @author yingzi
* @since 2025/10/28
*/
@AutoConfiguration(after = { NacosMcpAutoConfiguration.class })
@AutoConfiguration
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing @AutoConfiguration(after = { NacosMcpAutoConfiguration.class }) may cause bean initialization order issues. The nacosMcpOperationServiceMap bean from NacosMcpAutoConfiguration must be created before this configuration's beans are instantiated. Without the explicit ordering, Spring may attempt to create the client beans before the map is ready, leading to initialization failures or null dependency injection.

Copilot uses AI. Check for mistakes.
@EnableConfigurationProperties({ NacosMcpSseClientProperties.class, NacosMcpClientProperties.class})
@ConditionalOnProperty(prefix = "spring.ai.alibaba.mcp.nacos.client", name = { "enabled" }, havingValue = "true",
matchIfMissing = false)
Expand All @@ -48,11 +47,9 @@ public class NacosMcpSseClientAutoConfiguration {
@ConditionalOnProperty(prefix = "spring.ai.mcp.client", name = { "type" }, havingValue = "SYNC",
matchIfMissing = true)
public List<DistributedSyncMcpClient> sseWebFluxDistributedSyncClients(
ObjectProvider<Map<String, NacosMcpOperationService>> nacosMcpOperationServiceMapProvider,
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap,
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly injecting Map<String, NacosMcpOperationService> instead of using ObjectProvider removes the lazy resolution capability. The original ObjectProvider approach allowed the bean to be resolved at method execution time, which was safer when dealing with potential circular dependencies or when the map bean might not always be available. If NacosMcpAutoConfiguration is not loaded in certain scenarios, this will cause a bean creation failure instead of gracefully handling the absence.

Copilot uses AI. Check for mistakes.
NacosMcpSseClientProperties nacosMcpSseClientProperties, ApplicationContext applicationContext) {
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap = nacosMcpOperationServiceMapProvider.getObject();
List<DistributedSyncMcpClient> clients = new ArrayList<>();

nacosMcpSseClientProperties.getConnections().forEach((name, nacosSseParameters) -> {
SseWebFluxDistributedSyncMcpClient client = SseWebFluxDistributedSyncMcpClient.builder()
.serverName(nacosSseParameters.serviceName())
Expand All @@ -63,7 +60,6 @@ public List<DistributedSyncMcpClient> sseWebFluxDistributedSyncClients(
client.init();
client.subscribe();
clients.add(client);

});
return clients;
}
Expand All @@ -72,11 +68,9 @@ public List<DistributedSyncMcpClient> sseWebFluxDistributedSyncClients(
@ConditionalOnProperty(prefix = "spring.ai.mcp.client", name = { "type" }, havingValue = "ASYNC",
matchIfMissing = true)
public List<DistributedAsyncMcpClient> sseWebFluxDistributedAsyncClients(
ObjectProvider<Map<String, NacosMcpOperationService>> nacosMcpOperationServiceMapProvider,
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap,
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly injecting Map<String, NacosMcpOperationService> instead of using ObjectProvider removes the lazy resolution capability. The original ObjectProvider approach allowed the bean to be resolved at method execution time, which was safer when dealing with potential circular dependencies or when the map bean might not always be available. If NacosMcpAutoConfiguration is not loaded in certain scenarios, this will cause a bean creation failure instead of gracefully handling the absence.

Copilot uses AI. Check for mistakes.
NacosMcpSseClientProperties nacosMcpSseClientProperties, ApplicationContext applicationContext) {
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap = nacosMcpOperationServiceMapProvider.getObject();
List<DistributedAsyncMcpClient> clients = new ArrayList<>();

nacosMcpSseClientProperties.getConnections().forEach((name, nacosSseParameters) -> {
SseWebFluxDistributedAsyncMcpClient client = SseWebFluxDistributedAsyncMcpClient.builder()
.serverName(nacosSseParameters.serviceName())
Expand All @@ -86,7 +80,6 @@ public List<DistributedAsyncMcpClient> sseWebFluxDistributedAsyncClients(
.build();
client.init();
client.subscribe();

clients.add(client);
});
return clients;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,28 @@

package com.alibaba.cloud.ai.autoconfigure.mcp.discovery.client;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.alibaba.cloud.ai.mcp.discovery.client.transport.DistributedAsyncMcpClient;
import com.alibaba.cloud.ai.mcp.discovery.client.transport.DistributedSyncMcpClient;
import com.alibaba.cloud.ai.mcp.discovery.client.transport.streamable.StreamWebFluxDistributedAsyncMcpClient;
import com.alibaba.cloud.ai.mcp.discovery.client.transport.streamable.StreamWebFluxDistributedSyncMcpClient;
import com.alibaba.cloud.ai.mcp.nacos.NacosMcpClientProperties;
import com.alibaba.cloud.ai.mcp.nacos.service.NacosMcpOperationService;
import com.alibaba.cloud.ai.mcp.nacos.NacosMcpStreamableClientProperties;
import org.springframework.beans.factory.ObjectProvider;
import com.alibaba.cloud.ai.mcp.nacos.service.NacosMcpOperationService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
* @author yingzi
* @since 2025/10/28
*/
@AutoConfiguration(after = { NacosMcpAutoConfiguration.class })
@AutoConfiguration
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing @AutoConfiguration(after = { NacosMcpAutoConfiguration.class }) may cause bean initialization order issues. The nacosMcpOperationServiceMap bean from NacosMcpAutoConfiguration must be created before this configuration's beans are instantiated. Without the explicit ordering, Spring may attempt to create the client beans before the map is ready, leading to initialization failures or null dependency injection.

Suggested change
@AutoConfiguration
@AutoConfiguration(after = { com.alibaba.cloud.ai.autoconfigure.mcp.nacos.NacosMcpAutoConfiguration.class })

Copilot uses AI. Check for mistakes.
@EnableConfigurationProperties({ NacosMcpStreamableClientProperties.class, NacosMcpClientProperties.class})
@ConditionalOnProperty(prefix = "spring.ai.alibaba.mcp.nacos.client", name = { "enabled" }, havingValue = "true",
matchIfMissing = false)
Expand All @@ -48,11 +47,9 @@ public class NacosMcpStreamableClientAutoConfiguration {
@ConditionalOnProperty(prefix = "spring.ai.mcp.client", name = { "type" }, havingValue = "SYNC",
matchIfMissing = true)
public List<DistributedSyncMcpClient> streamableWebFluxDistributedSyncClients(
ObjectProvider<Map<String, NacosMcpOperationService>> nacosMcpOperationServiceMapProvider,
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap,
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly injecting Map<String, NacosMcpOperationService> instead of using ObjectProvider removes the lazy resolution capability. The original ObjectProvider approach allowed the bean to be resolved at method execution time, which was safer when dealing with potential circular dependencies or when the map bean might not always be available. If NacosMcpAutoConfiguration is not loaded in certain scenarios, this will cause a bean creation failure instead of gracefully handling the absence.

Copilot uses AI. Check for mistakes.
NacosMcpStreamableClientProperties nacosMcpStreamableClientProperties, ApplicationContext applicationContext) {
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap = nacosMcpOperationServiceMapProvider.getObject();
List<DistributedSyncMcpClient> clients = new ArrayList<>();

nacosMcpStreamableClientProperties.getConnections().forEach((name, nacosSseParameters) -> {
StreamWebFluxDistributedSyncMcpClient client = StreamWebFluxDistributedSyncMcpClient.builder()
.serverName(nacosSseParameters.serviceName())
Expand All @@ -63,7 +60,6 @@ public List<DistributedSyncMcpClient> streamableWebFluxDistributedSyncClients(
client.init();
client.subscribe();
clients.add(client);

});
return clients;
}
Expand All @@ -72,11 +68,9 @@ public List<DistributedSyncMcpClient> streamableWebFluxDistributedSyncClients(
@ConditionalOnProperty(prefix = "spring.ai.mcp.client", name = { "type" }, havingValue = "ASYNC",
matchIfMissing = true)
public List<DistributedAsyncMcpClient> streamableWebFluxDistributedAsyncClients(
ObjectProvider<Map<String, NacosMcpOperationService>> nacosMcpOperationServiceMapProvider,
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap,
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly injecting Map<String, NacosMcpOperationService> instead of using ObjectProvider removes the lazy resolution capability. The original ObjectProvider approach allowed the bean to be resolved at method execution time, which was safer when dealing with potential circular dependencies or when the map bean might not always be available. If NacosMcpAutoConfiguration is not loaded in certain scenarios, this will cause a bean creation failure instead of gracefully handling the absence.

Copilot uses AI. Check for mistakes.
NacosMcpStreamableClientProperties nacosMcpStreamableClientProperties, ApplicationContext applicationContext) {
Map<String, NacosMcpOperationService> nacosMcpOperationServiceMap = nacosMcpOperationServiceMapProvider.getObject();
List<DistributedAsyncMcpClient> clients = new ArrayList<>();

nacosMcpStreamableClientProperties.getConnections().forEach((name, nacosSseParameters) -> {
StreamWebFluxDistributedAsyncMcpClient client = StreamWebFluxDistributedAsyncMcpClient.builder()
.serverName(nacosSseParameters.serviceName())
Expand All @@ -86,7 +80,6 @@ public List<DistributedAsyncMcpClient> streamableWebFluxDistributedAsyncClients(
.build();
client.init();
client.subscribe();

clients.add(client);
});
return clients;
Expand Down
Loading