Repository: alibaba/nacos
Pull request #13424: fix ai api bugs
Author: login: luoxiner
Created: 2025-05-23T06:07:29Z | Merged: 2025-05-23T06:32:49Z

Please do not create a Pull Request without creating an issue first.

## What is the purpose of the change

Fix ai admin api bugs.

## Brief changelog

XX

## Verifying this change

XXXX

Follow this checklist to help us incorporate your contribution quickly and easily:

* [ ] Make sure there is a Github issue filed for the change (usually before you start working on it). Trivial changes like typos do not require a Github issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue.
* [ ] Format the pull request title like `[ISSUE #123] Fix UnknownException when host config not exist`. Each commit in the pull request should have a meaningful subject line and body.
* [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
* [ ] Write necessary unit-test to verify your logic correction, more mock a little better when cross module dependency exist. If the new feature or significant change is committed, please remember to add integration-test in [test module](https://github.com/alibaba/nacos/tree/master/test).
* [ ] Run `mvn -B clean package apache-rat:check findbugs:findbugs -Dmaven.test.skip=true` to make sure basic checks pass. Run `mvn clean install -DskipITs` to make sure unit-test pass. Run `mvn clean test-compile failsafe:integration-test`  to make sure integration-test pass.




Diff:
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/constant/Constants.java b/ai/src/main/java/com/alibaba/nacos/ai/constant/Constants.java
index 72d2a4eb1ad..ccb5fb37a33 100644
--- a/ai/src/main/java/com/alibaba/nacos/ai/constant/Constants.java
+++ b/ai/src/main/java/com/alibaba/nacos/ai/constant/Constants.java
@@ -27,8 +27,6 @@ public class Constants {
     
     public static final String MCP_ADMIN_PATH = "/v3/admin" + MCP_PATH;
     
-    public static final String MCP_REGISTRY_PATH = "/v3/mcp-registry";
-    
     public static final String MCP_CONSOLE_PATH = "/v3/console" + MCP_PATH;
     
     public static final String MCP_LIST_SEARCH_ACCURATE = "accurate";
@@ -65,10 +63,23 @@ public class Constants {
     
     public static final String PROTOCOL_TYPE_HTTP = "http";
     
+    public static final String PROTOCOL_TYPE_HTTPS = "https";
+    
     public static final String SERVER_EXPORT_PATH_KEY = "exportPath";
     
     public static final String MCP_SERVER_NAME_TAG_KEY_PREFIX = "mcpServerName=";
     
     public static final int MAX_LIST_SIZE = 100;
     
+    public static final String RELEASE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+    
+    public static final String CONFIG_TAGS_NAME = "config_tags";
+    
+    public static final String META_PATH = "path";
+    
+    public static final String SERVER_VERSION_CONFIG_DATA_ID_TEMPLATE = "%s" + MCP_SERVER_VERSION_DATA_ID_SUFFIX;
+    
+    public static final String SERVER_SPECIFICATION_CONFIG_DATA_ID_TEMPLATE = "%s-%s" + MCP_SERVER_SPEC_DATA_ID_SUFFIX;
+    
+    public static final String SERVER_TOOLS_SPEC_CONFIG_DATA_ID_TEMPLATE = "%s-%s" + MCP_SERVER_TOOL_DATA_ID_SUFFIX;
 }
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpUpdateForm.java b/ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpUpdateForm.java
index 6f199641e77..df3491aeb83 100644
--- a/ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpUpdateForm.java
+++ b/ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpUpdateForm.java
@@ -28,7 +28,7 @@ public class McpUpdateForm extends McpDetailForm {
     @Serial
     private static final long serialVersionUID = 4144251088520249913L;
     
-    private Boolean latest;
+    private boolean latest = true;
     
     public Boolean getLatest() {
         return latest;
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java b/ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java
index 8c87a3b4569..05d96d5c197 100644
--- a/ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java
+++ b/ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java
@@ -18,6 +18,7 @@
 
 import com.alibaba.nacos.ai.constant.Constants;
 import com.alibaba.nacos.ai.model.mcp.McpServerIndexData;
+import com.alibaba.nacos.ai.utils.McpConfigUtils;
 import com.alibaba.nacos.api.ai.model.mcp.McpServerVersionInfo;
 import com.alibaba.nacos.api.model.Page;
 import com.alibaba.nacos.api.model.response.Namespace;
@@ -65,6 +66,7 @@ public PlainMcpServerIndex(NamespaceOperationService namespaceOperationService,
     
     /**
      * Search Mcp server by name and namespaceId.
+     * If namespaceId is empty, we search all the namespace.
      *
      * @param namespaceId namespaceId empty for all namespaces
      * @param name        mcp server name, empty for all servers
@@ -78,33 +80,44 @@ public Page<McpServerIndexData> searchMcpServerByName(String namespaceId, String
                                                           String search, int offset, int limit) {
         List<String> namespaceIdList;
         if (StringUtils.isEmpty(namespaceId)) {
-            namespaceIdList = getNamespaceList();
+            namespaceIdList = fetchOrderedNamespaceList();
         } else {
             namespaceIdList = Collections.singletonList(namespaceId);
         }
         
-        int searchedItemsCount = 0;
         int totalCount = 0;
         int remains = limit;
+        int searchedItemsCount = 0;
         List<McpServerIndexData> result = new ArrayList<>();
         
-        for (String nsId : namespaceIdList) {
-            Page<ConfigInfo> countInfo = searchMcpServers(nsId, name, search, 1);
-            if (offset >= searchedItemsCount && offset <= searchedItemsCount + countInfo.getTotalCount()) {
-                Page<ConfigInfo> pageConfigs = searchMcpServers(nsId, name, search, 
-                        offset - searchedItemsCount + remains);
-                List<McpServerIndexData> indexDataList = pageConfigs.getPageItems()
-                        .stream().skip(offset - searchedItemsCount)
-                        .map(this::mapMcpServerVersionConfigToIndexData).toList();
-                result.addAll(indexDataList);
+        for (String ns : namespaceIdList) {
+            Page<ConfigInfo> countInfo = searchMcpServers(ns, name, search, 1);
+            int totalServerInNs = countInfo.getTotalCount();
+            
+            // find the first namespace which match the offset.
+            if (offset >= searchedItemsCount && offset <= searchedItemsCount + totalServerInNs) {
+                int currentSearchLimit = offset - searchedItemsCount + remains;
+                Page<ConfigInfo> serverInfos = searchMcpServers(ns, name, search, currentSearchLimit);
+                if (CollectionUtils.isEmpty(serverInfos.getPageItems())) {
+                    continue;
+                }
+                
+                List<McpServerIndexData> indexDataList = serverInfos.getPageItems()
+                        .stream()
+                        .skip(offset - searchedItemsCount)
+                        .map(this::mapMcpServerVersionConfigToIndexData)
+                        .toList();
                 remains -= indexDataList.size();
+                result.addAll(indexDataList);
             } else if (remains > 0 && remains < limit) {
-                Page<ConfigInfo> pageConfigs = searchMcpServers(nsId, name, search, remains);
-                remains -= pageConfigs.getPageItems().size();
+                Page<ConfigInfo> pageConfigs = searchMcpServers(ns, name, search, remains);
                 List<McpServerIndexData> indexDataList = pageConfigs.getPageItems().stream()
-                        .map(this::mapMcpServerVersionConfigToIndexData).toList();
+                        .map(this::mapMcpServerVersionConfigToIndexData)
+                        .toList();
+                remains -= pageConfigs.getPageItems().size();
                 result.addAll(indexDataList);
             }
+            
             searchedItemsCount += countInfo.getPageItems().size();
             totalCount += countInfo.getTotalCount();
         }
@@ -122,30 +135,30 @@ private McpServerIndexData mapMcpServerVersionConfigToIndexData(ConfigInfo confi
         McpServerVersionInfo versionInfo = JacksonUtils.toObj(configInfo.getContent(), 
                 McpServerVersionInfo.class);
         data.setId(versionInfo.getId());
-        data.setName(versionInfo.getName());
         data.setNamespaceId(configInfo.getTenant());
         return data;
     }
     
-    private Page<ConfigInfo> searchMcpServers(String namespace, String serverName, String search, 
-                                              int limit) {
+    private Page<ConfigInfo> searchMcpServers(String namespace, String serverName, String search, int limit) {
         HashMap<String, Object> advanceInfo = new HashMap<>(1);
         if (Objects.isNull(serverName)) {
             serverName = StringUtils.EMPTY;
         }
         
         String dataId = Constants.ALL_PATTERN;
-        if (Constants.MCP_LIST_SEARCH_BLUR.equals(search)) {
-            advanceInfo.put("config_tags",
-                    Constants.MCP_SERVER_NAME_TAG_KEY_PREFIX + Constants.ALL_PATTERN + serverName + Constants.ALL_PATTERN);
+        if (Constants.MCP_LIST_SEARCH_BLUR.equals(search) || StringUtils.isEmpty(serverName)) {
+            String nameTag = McpConfigUtils.formatServerNameTagBlurSearchValue(serverName);
+            advanceInfo.put(Constants.CONFIG_TAGS_NAME, nameTag);
+            search = Constants.MCP_LIST_SEARCH_BLUR;
         } else {
-            advanceInfo.put("config_tags",
-                    Constants.MCP_SERVER_NAME_TAG_KEY_PREFIX +  serverName);
-            dataId = "";
+            advanceInfo.put(Constants.CONFIG_TAGS_NAME,
+                    McpConfigUtils.formatServerNameTagAccurateSearchValue(serverName));
+            dataId = null;
         }
         
-        return configDetailService.findConfigInfoPage(search, 1, limit,
-                dataId, Constants.MCP_SERVER_VERSIONS_GROUP, namespace, advanceInfo);
+        return configDetailService.findConfigInfoPage(search, 1, limit, 
+                dataId, Constants.MCP_SERVER_VERSIONS_GROUP, 
+                namespace, advanceInfo);
     }
 
     /**
@@ -156,18 +169,16 @@ private Page<ConfigInfo> searchMcpServers(String namespace, String serverName, S
      */
     @Override
     public McpServerIndexData getMcpServerById(String id) {
-        List<String> namespaceList = getNamespaceList();
+        if (StringUtils.isEmpty(id)) {
+            return null;
+        }
+        
+        List<String> namespaceList = fetchOrderedNamespaceList();
         for (String namespaceId : namespaceList) {
             ConfigQueryChainRequest request = buildConfigQueryChainRequest(namespaceId, id);
             ConfigQueryChainResponse response = configQueryChainService.handle(request);
-            if (ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_FOUND_FORMAL.equals(response.getStatus())) {
-                McpServerIndexData data = new McpServerIndexData();
-                data.setId(id);
-                data.setNamespaceId(namespaceId);
-                String content = response.getContent();
-                McpServerVersionInfo versionInfo = JacksonUtils.toObj(content, McpServerVersionInfo.class);
-                data.setName(versionInfo.getName());
-                return data;
+            if (McpConfigUtils.isConfigFound(response.getStatus())) {
+                return McpServerIndexData.newIndexData(id, namespaceId);
             }
         }
         return null;
@@ -176,7 +187,7 @@ public McpServerIndexData getMcpServerById(String id) {
     private ConfigQueryChainRequest buildConfigQueryChainRequest(String namespaceId, String serverId) {
         ConfigQueryChainRequest request = new ConfigQueryChainRequest();
         request.setTenant(namespaceId);
-        request.setDataId(serverId + Constants.MCP_SERVER_VERSION_DATA_ID_SUFFIX);
+        request.setDataId(McpConfigUtils.formatServerVersionInfoDataId(serverId));
         request.setGroup(Constants.MCP_SERVER_VERSIONS_GROUP);
         return request;
     }
@@ -190,16 +201,18 @@ private ConfigQueryChainRequest buildConfigQueryChainRequest(String namespaceId,
      */
     @Override
     public McpServerIndexData getMcpServerByName(String namespaceId, String name) {
-        Page<McpServerIndexData> mcpServerIndexDataPage = searchMcpServerByName(namespaceId, name, Constants.MCP_LIST_SEARCH_ACCURATE, 0, 1);
-        if (CollectionUtils.isNotEmpty(mcpServerIndexDataPage.getPageItems())) {
-            return mcpServerIndexDataPage.getPageItems().get(0);
+        Page<McpServerIndexData> indexDataPage = searchMcpServerByName(namespaceId, name, 
+                Constants.MCP_LIST_SEARCH_ACCURATE, 0, 1);
+        if (CollectionUtils.isNotEmpty(indexDataPage.getPageItems())) {
+            return indexDataPage.getPageItems().get(0);
         }
         return null;
     }
     
-    public List<String> getNamespaceList() {
+    private List<String> fetchOrderedNamespaceList() {
         return namespaceOperationService.getNamespaceList().stream()
                 .sorted(Comparator.comparing(Namespace::getNamespace))
-                .map(Namespace::getNamespace).toList();
+                .map(Namespace::getNamespace)
+                .toList();
     }
 }
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/model/mcp/McpServerIndexData.java b/ai/src/main/java/com/alibaba/nacos/ai/model/mcp/McpServerIndexData.java
index f178aded1f0..efc1ac19475 100644
--- a/ai/src/main/java/com/alibaba/nacos/ai/model/mcp/McpServerIndexData.java
+++ b/ai/src/main/java/com/alibaba/nacos/ai/model/mcp/McpServerIndexData.java
@@ -25,10 +25,21 @@ public class McpServerIndexData {
 
     private String id;
 
-    private String name;
-
     private String namespaceId;
 
+    /**
+     * Factory method for index data.
+     * @param id server id
+     * @param namespaceId namespaceId
+     * @return index
+     */
+    public static McpServerIndexData newIndexData(String id, String namespaceId) {
+        McpServerIndexData data = new McpServerIndexData();
+        data.setNamespaceId(namespaceId);
+        data.setId(id);
+        return data;
+    }
+
     public String getId() {
         return id;
     }
@@ -37,14 +48,6 @@ public void setId(String id) {
         this.id = id;
     }
 
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public String getNamespaceId() {
         return namespaceId;
     }
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java b/ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java
index 12729fa0caf..24456643e91 100644
--- a/ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java
+++ b/ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java
@@ -20,6 +20,8 @@
 import com.alibaba.nacos.ai.index.McpServerIndex;
 import com.alibaba.nacos.ai.model.mcp.McpServerIndexData;
 import com.alibaba.nacos.ai.model.mcp.McpServerStorageInfo;
+import com.alibaba.nacos.ai.utils.McpConfigUtils;
+import com.alibaba.nacos.ai.utils.McpProtocolUtils;
 import com.alibaba.nacos.api.ai.constant.AiConstants;
 import com.alibaba.nacos.api.ai.model.mcp.McpCapability;
 import com.alibaba.nacos.api.ai.model.mcp.McpEndpointInfo;
@@ -36,6 +38,7 @@
 import com.alibaba.nacos.api.model.Page;
 import com.alibaba.nacos.api.model.v2.ErrorCode;
 import com.alibaba.nacos.api.naming.pojo.Instance;
+import com.alibaba.nacos.common.utils.CollectionUtils;
 import com.alibaba.nacos.common.utils.JacksonUtils;
 import com.alibaba.nacos.common.utils.StringUtils;
 import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
@@ -52,7 +55,6 @@
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -62,15 +64,18 @@
 import java.util.stream.Collectors;
 
 import static com.alibaba.nacos.ai.constant.Constants.MCP_SERVER_CONFIG_MARK;
+import static com.alibaba.nacos.ai.utils.McpConfigUtils.buildMcpServerVersionConfigTags;
 
 /**
  * Nacos AI MCP server operation service.
  * Currently, mcp server is present by there configs:
- * 1. mcp server version info {@link McpServerVersionInfo}
+ * 1. mcp server version info {@link McpServerVersionInfo} 
  * 2. mcp server description for specified version {@link McpServerDetailInfo}
  * 3. mcp tools info {@link McpToolSpecification}
  * when create the mcp server, we will tag the {@link McpServerVersionInfo}
  * with mcp servername for name fuzzy search.
+ * 
+ * 
  *
  * @author xiweng.yy
  */
@@ -88,8 +93,10 @@ public class McpServerOperationService {
     private final McpServerIndex mcpServerIndex;
 
     public McpServerOperationService(ConfigQueryChainService configQueryChainService,
-                                     ConfigOperationService configOperationService, McpToolOperationService toolOperationService, 
-                                     McpEndpointOperationService endpointOperationService, McpServerIndex mcpServerIndex) {
+                                     ConfigOperationService configOperationService, 
+                                     McpToolOperationService toolOperationService, 
+                                     McpEndpointOperationService endpointOperationService, 
+                                     McpServerIndex mcpServerIndex) {
         this.configQueryChainService = configQueryChainService;
         this.configOperationService = configOperationService;
         this.toolOperationService = toolOperationService;
@@ -108,24 +115,30 @@ public McpServerOperationService(ConfigQueryChainService configQueryChainService
      * @param pageSize    page size each page
      * @return list of {@link McpServerBasicInfo} matched input parameters.
      */
-    public Page<McpServerBasicInfo> listMcpServerWithPage(String namespaceId, String mcpName, String search, int pageNo,
-                                                          int pageSize) {
-        Page<McpServerIndexData> indexData = mcpServerIndex.searchMcpServerByName(namespaceId, mcpName, search,
-                pageSize * (pageNo - 1), pageSize);
-        return getMcpServerBasicInfoPage(indexData);
+    public Page<McpServerBasicInfo> listMcpServerWithPage(String namespaceId, String mcpName, String search, 
+                                                          int pageNo, int pageSize) {
+        int offset = pageSize * (pageNo - 1);
+        Page<McpServerIndexData> indexData = mcpServerIndex.searchMcpServerByName(
+                namespaceId, mcpName, search, offset, pageSize);
+        return mapIndexToBasicServerInfo(indexData);
     }
     
-    private Page<McpServerBasicInfo> getMcpServerBasicInfoPage(Page<McpServerIndexData> indexData) {
-        List<McpServerBasicInfo> finalResult = indexData.getPageItems().stream().map((index) -> {
-            ConfigQueryChainRequest request = buildQueryMcpServerVersionInfoRequest(index.getNamespaceId(), index.getId());
-            ConfigQueryChainResponse response = configQueryChainService.handle(request);
-            return transferToMcpServerVersionInfo(response.getContent());
-        }).collect(Collectors.toList());
-
+    private Page<McpServerBasicInfo> mapIndexToBasicServerInfo(Page<McpServerIndexData> indexData) {
         Page<McpServerBasicInfo> result = new Page<>();
         result.setTotalCount(indexData.getTotalCount());
         result.setPageNumber(indexData.getPageNumber());
         result.setPagesAvailable(indexData.getPagesAvailable());
+        
+        List<McpServerBasicInfo> finalResult = Collections.emptyList();
+        
+        if (CollectionUtils.isNotEmpty(indexData.getPageItems())) {
+            finalResult = indexData.getPageItems().stream()
+                    .map((index) -> buildQueryMcpServerVersionInfoRequest(index.getNamespaceId(), index.getId()))
+                    .map(configQueryChainService::handle)
+                    .map(ConfigQueryChainResponse::getContent)
+                    .map(this::transferToMcpServerVersionInfo)
+                    .collect(Collectors.toList());
+        }
         result.setPageItems(finalResult);
         return result;
     }
@@ -141,15 +154,16 @@ private Page<McpServerBasicInfo> getMcpServerBasicInfoPage(Page<McpServerIndexDa
      * @param limit       limit
      * @return list of {@link McpServerBasicInfo} matched input parameters.
      */
-    public Page<McpServerBasicInfo> listMcpServerWithOffset(String namespaceId, String mcpName, String search, int offset,
-                                                  int limit) {
-        Page<McpServerIndexData> indexData = mcpServerIndex.searchMcpServerByName(namespaceId, mcpName, search, offset, limit);
-
-        return getMcpServerBasicInfoPage(indexData);
+    public Page<McpServerBasicInfo> listMcpServerWithOffset(String namespaceId, String mcpName, String search, 
+                                                            int offset, int limit) {
+        Page<McpServerIndexData> indexData = mcpServerIndex.searchMcpServerByName(
+                namespaceId, mcpName, search, offset, limit);
+        return mapIndexToBasicServerInfo(indexData);
     }
     
     /**
      * Get specified mcp server detail info.
+     * mcpServerId or namespaceId + mcpServerName is needed.
      *
      * @param namespaceId namespace id of mcp server
      * @param mcpServerId id of mcp server
@@ -177,43 +191,44 @@ public McpServerDetailInfo getMcpServerDetail(String namespaceId, String mcpServ
         
         ConfigQueryChainRequest request = buildQueryMcpServerRequest(namespaceId, mcpServerId, version);
         ConfigQueryChainResponse response = configQueryChainService.handle(request);
-        if (ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND == response.getStatus()) {
+        if (McpConfigUtils.isConfigNotFound(response.getStatus())) {
             throw new NacosApiException(NacosApiException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
                     String.format("mcp server `%s` for version `%s` not found", mcpServerId, version));
         }
+        
         McpServerStorageInfo serverSpecification = JacksonUtils.toObj(response.getContent(),
                 McpServerStorageInfo.class);
+        
         McpServerDetailInfo result = new McpServerDetailInfo();
+        result.setId(mcpServerId);
+        result.setNamespaceId(namespaceId);
+        BeanUtils.copyProperties(serverSpecification, result);
+        
         List<ServerVersionDetail> versionDetails = mcpServerVersionInfo.getVersionDetails();
+        String latestVersion = mcpServerVersionInfo.getLatestPublishedVersion();
         for (ServerVersionDetail versionDetail : versionDetails) {
-            if (versionDetail.getVersion().equals(mcpServerVersionInfo.getLatestPublishedVersion())) {
-                versionDetail.setIs_latest(true);
-            } else {
-                versionDetail.setIs_latest(false);
-            }
+            versionDetail.setIs_latest(versionDetail.getVersion().equals(latestVersion));
         }
-        
         result.setAllVersions(mcpServerVersionInfo.getVersionDetails());
-        BeanUtils.copyProperties(serverSpecification, result);
-        if (result.getVersionDetail().getVersion().equals(mcpServerVersionInfo.getLatestPublishedVersion())) {
-            result.getVersionDetail().setIs_latest(true);
-        } else {
-            result.getVersionDetail().setIs_latest(false);
-        }
-        if (null != serverSpecification.getToolsDescriptionRef()) {
+
+        ServerVersionDetail versionDetail = result.getVersionDetail();
+        versionDetail.setIs_latest(versionDetail.getVersion().equals(latestVersion));
+        result.setVersion(versionDetail.getVersion());
+        
+        if (Objects.nonNull(serverSpecification.getToolsDescriptionRef())) {
             McpToolSpecification toolSpec = toolOperationService.getMcpTool(namespaceId,
                     serverSpecification.getToolsDescriptionRef());
             result.setToolSpec(toolSpec);
         }
+        
         if (!AiConstants.Mcp.MCP_PROTOCOL_STDIO.equalsIgnoreCase(serverSpecification.getProtocol())) {
             injectBackendEndpointRef(namespaceId, result);
         }
-        
-        result.setNamespaceId(namespaceId);
         return result;
     }
     
-    public McpServerVersionInfo getMcpServerVersionInfo(String namespaceId, String mcpServerId) throws NacosApiException {
+    public McpServerVersionInfo getMcpServerVersionInfo(String namespaceId, 
+                                                        String mcpServerId) throws NacosApiException {
         if (StringUtils.isEmpty(namespaceId)) {
             McpServerIndexData indexData = mcpServerIndex.getMcpServerById(mcpServerId);
             namespaceId = indexData.getNamespaceId();
@@ -221,7 +236,7 @@ public McpServerVersionInfo getMcpServerVersionInfo(String namespaceId, String m
 
         ConfigQueryChainRequest request = buildQueryMcpServerVersionInfoRequest(namespaceId, mcpServerId);
         ConfigQueryChainResponse response = configQueryChainService.handle(request);
-        if (ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND == response.getStatus()) {
+        if (McpConfigUtils.isConfigNotFound(response.getStatus())) {
             throw new NacosApiException(NacosApiException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
                     String.format("mcp server `%s` not found", mcpServerId));
         }
@@ -231,7 +246,9 @@ public McpServerVersionInfo getMcpServerVersionInfo(String namespaceId, String m
     
     private void injectBackendEndpointRef(String namespaceId, McpServerDetailInfo detailInfo) throws NacosException {
         List<Instance> instances;
-        if (StringUtils.startsWith(detailInfo.getProtocol(), Constants.PROTOCOL_TYPE_HTTP)) {
+        
+        // inject translator address to the mcp server.
+        if (McpProtocolUtils.isProtocolNeedTranslator(detailInfo.getProtocol())) {
             McpServiceRef mcpServiceRef = new McpServiceRef();
             mcpServiceRef.setServiceName(detailInfo.getName());
             mcpServiceRef.setGroupName(Constants.MCP_SERVER_PROTOCOL_TRANSLATOR_GROUP);
@@ -248,7 +265,7 @@ private void injectBackendEndpointRef(String namespaceId, McpServerDetailInfo de
             mcpEndpointInfo.setPort(each.getPort());
             String exportPath = detailInfo.getRemoteServerConfig().getExportPath();
             if (Constants.PROTOCOL_TYPE_HTTP.equals(detailInfo.getProtocol())) {
-                exportPath = each.getMetadata().get("path");
+                exportPath = each.getMetadata().get(Constants.META_PATH);
             }
             mcpEndpointInfo.setPath(exportPath);
             backendEndpoints.add(mcpEndpointInfo);
@@ -265,7 +282,7 @@ private void injectBackendEndpointRef(String namespaceId, McpServerDetailInfo de
      * @param endpointSpecification mcp server endpoint specification, see {@link McpEndpointSpec}, optional
      * @throws NacosException any exception during handling
      */
-    public void createMcpServer(String namespaceId, McpServerBasicInfo serverSpecification,
+    public String createMcpServer(String namespaceId, McpServerBasicInfo serverSpecification,
             McpToolSpecification toolSpecification, McpEndpointSpec endpointSpecification) throws NacosException {
 
         String existId = resolveMcpServerId(namespaceId, serverSpecification.getName(), StringUtils.EMPTY);
@@ -274,22 +291,39 @@ public void createMcpServer(String namespaceId, McpServerBasicInfo serverSpecifi
                     String.format("mcp server `%s` has existed, please update it rather than create.", serverSpecification.getName()));
         }
 
-        String id = UUID.randomUUID().toString();
-        McpServerIndexData indexData = new McpServerIndexData();
-        indexData.setId(id);
-        indexData.setNamespaceId(namespaceId);
-        indexData.setName(serverSpecification.getName());
-        
         ServerVersionDetail versionDetail = serverSpecification.getVersionDetail();
+        if (Objects.isNull(versionDetail) || StringUtils.isEmpty(versionDetail.getVersion())) {
+            throw new NacosApiException(NacosApiException.INVALID_PARAM, ErrorCode.PARAMETER_VALIDATE_ERROR,
+                    "Version must be specified in parameter `serverSpecification`");
+        }
+        
+        String id = UUID.randomUUID().toString();
+        serverSpecification.setId(id);
         ZonedDateTime currentTime = ZonedDateTime.now(ZoneOffset.UTC);
-        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(Constants.RELEASE_DATE_FORMAT);
         String formattedCurrentTime = currentTime.format(formatter);
         versionDetail.setRelease_date(formattedCurrentTime);
         
         McpServerStorageInfo newSpecification = new McpServerStorageInfo();
         BeanUtils.copyProperties(serverSpecification, newSpecification);
-        injectToolAndEndpoint(namespaceId, serverSpecification.getName(), newSpecification, toolSpecification, endpointSpecification);
+        injectToolAndEndpoint(namespaceId, serverSpecification.getId(), newSpecification, 
+                toolSpecification, endpointSpecification);
+
+        McpServerVersionInfo versionInfo = buildServerVersionInfo(serverSpecification, id, versionDetail);
+        
+        ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
+        configRequestInfo.setUpdateForExist(Boolean.FALSE);
 
+        ConfigFormV3 mcpServerVersionForm = buildMcpServerVersionForm(namespaceId, versionInfo);
+        configOperationService.publishConfig(mcpServerVersionForm, configRequestInfo, null);
+        
+        ConfigForm configForm = buildMcpConfigForm(namespaceId, id, versionDetail.getVersion(), newSpecification);
+        configOperationService.publishConfig(configForm, configRequestInfo, null);
+        return id;
+    }
+
+    private static McpServerVersionInfo buildServerVersionInfo(McpServerBasicInfo serverSpecification, String id, 
+                                                               ServerVersionDetail versionDetail) {
         McpServerVersionInfo versionInfo = new McpServerVersionInfo();
         versionInfo.setName(serverSpecification.getName());
         versionInfo.setId(id);
@@ -300,16 +334,9 @@ public void createMcpServer(String namespaceId, McpServerBasicInfo serverSpecifi
         versionInfo.setCapabilities(serverSpecification.getCapabilities());
         versionInfo.setLatestPublishedVersion(serverSpecification.getVersionDetail().getVersion());
         versionInfo.setVersions(Collections.singletonList(versionDetail));
-        
-        ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
-        configRequestInfo.setUpdateForExist(Boolean.FALSE);
-        ConfigFormV3 mcpServerVersionForm = buildMcpServerVersionForm(namespaceId, versionInfo);
-        configOperationService.publishConfig(mcpServerVersionForm, configRequestInfo, null);
-        
-        ConfigForm configForm = buildMcpConfigForm(namespaceId, id, versionDetail.getVersion(), newSpecification);
-        configOperationService.publishConfig(configForm, configRequestInfo, null);
+        return versionInfo;
     }
-    
+
     /**
      * Update existed mcp server.
      *
@@ -325,20 +352,22 @@ public void createMcpServer(String namespaceId, McpServerBasicInfo serverSpecifi
      */
     public void updateMcpServer(String namespaceId, boolean isPublish, McpServerBasicInfo serverSpecification,
             McpToolSpecification toolSpecification, McpEndpointSpec endpointSpecification) throws NacosException {
+        
         String mcpServerId = serverSpecification.getId();
         mcpServerId = resolveMcpServerId(namespaceId, serverSpecification.getName(), mcpServerId);
-        
-        McpServerIndexData indexData = mcpServerIndex.getMcpServerById(mcpServerId);
-        if (Objects.isNull(indexData)) {
-            throw new NacosApiException(NacosApiException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
-                    String.format("mcp server `%s` not found", mcpServerId));
+        checkMcpServerIndex(mcpServerId);
+
+        ServerVersionDetail versionDetail = serverSpecification.getVersionDetail();
+        if (Objects.isNull(versionDetail) || StringUtils.isEmpty(versionDetail.getVersion())) {
+            throw new NacosApiException(NacosApiException.INVALID_PARAM, ErrorCode.PARAMETER_VALIDATE_ERROR,
+                    "Version must be specified in parameter `serverSpecification`");
         }
 
-        String updateVersion = serverSpecification.getVersionDetail().getVersion();
-        
+        String updateVersion = versionDetail.getVersion();
         McpServerStorageInfo newSpecification = new McpServerStorageInfo();
         BeanUtils.copyProperties(serverSpecification, newSpecification);
         injectToolAndEndpoint(namespaceId, mcpServerId, newSpecification, toolSpecification, endpointSpecification);
+        
         ConfigForm configForm = buildMcpConfigForm(namespaceId, mcpServerId, updateVersion, newSpecification);
         configOperationService.publishConfig(configForm, new ConfigRequestInfo(), null);
 
@@ -346,9 +375,9 @@ public void updateMcpServer(String namespaceId, boolean isPublish, McpServerBasi
         List<ServerVersionDetail> versionDetails = mcpServerVersionInfo.getVersionDetails();
         Set<String> versionSet = versionDetails.stream().map(ServerVersionDetail::getVersion).collect(Collectors.toSet());
         if (!versionSet.contains(updateVersion)) {
-            ServerVersionDetail versionDetail = new ServerVersionDetail();
-            versionDetail.setVersion(updateVersion);
-            versionDetails.add(versionDetail);
+            ServerVersionDetail version = new ServerVersionDetail();
+            version.setVersion(updateVersion);
+            versionDetails.add(version);
             mcpServerVersionInfo.setVersions(versionDetails);
         }
 
@@ -361,16 +390,16 @@ public void updateMcpServer(String namespaceId, boolean isPublish, McpServerBasi
             mcpServerVersionInfo.setCapabilities(newSpecification.getCapabilities());
             mcpServerVersionInfo.setLatestPublishedVersion(updateVersion);
 
-            for (ServerVersionDetail versionDetail : versionDetails) {
-                if (versionDetail.getVersion().equals(updateVersion)) {
+            for (ServerVersionDetail detail : versionDetails) {
+                if (detail.getVersion().equals(updateVersion)) {
                     ZonedDateTime currentTime = ZonedDateTime.now(ZoneOffset.UTC);
                     DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
                     String formattedCurrentTime = currentTime.format(formatter);
-                    versionDetail.setRelease_date(formattedCurrentTime);
-                    versionDetail.setIs_latest(true);
+                    detail.setRelease_date(formattedCurrentTime);
+                    detail.setIs_latest(true);
                     break;
                 } else {
-                    versionDetail.setIs_latest(false);
+                    detail.setIs_latest(false);
                 }
             }
             mcpServerVersionInfo.setVersions(versionDetails);
@@ -403,10 +432,10 @@ public void deleteMcpServer(String namespaceId, String mcpName, String mcpServer
         for (String versionNeedDelete : versionsNeedDelete) {
             toolOperationService.deleteMcpTool(namespaceId, mcpServerId, versionNeedDelete);
             endpointOperationService.deleteMcpServerEndpointService(namespaceId, mcpServerVersionInfo.getName());
-            String serverSpecDataId = mcpServerId + "-" + versionNeedDelete + Constants.MCP_SERVER_SPEC_DATA_ID_SUFFIX;
+            String serverSpecDataId = McpConfigUtils.formatServerSpecInfoDataId(mcpServerId, versionNeedDelete);
             configOperationService.deleteConfig(serverSpecDataId,
                     Constants.MCP_SERVER_GROUP, namespaceId, null, null, "nacos", null);
-            String serverVersionDataId = mcpServerId + Constants.MCP_SERVER_VERSION_DATA_ID_SUFFIX;
+            String serverVersionDataId = McpConfigUtils.formatServerVersionInfoDataId(mcpServerId);
             configOperationService.deleteConfig(serverVersionDataId, Constants.MCP_SERVER_VERSIONS_GROUP, namespaceId, null, null, "nacos", null);
         }
     }
@@ -414,11 +443,12 @@ public void deleteMcpServer(String namespaceId, String mcpName, String mcpServer
     private void injectToolAndEndpoint(String namespaceId, String mcpServerId, McpServerStorageInfo serverSpecification,
             McpToolSpecification toolSpecification, McpEndpointSpec endpointSpecification) throws NacosException {
         serverSpecification.setCapabilities(new LinkedList<>());
-        String currentVersion = serverSpecification.getVersionDetail().getVersion();
         if (null != toolSpecification && null != toolSpecification.getTools() && !toolSpecification.getTools().isEmpty()) {
-            toolOperationService.refreshMcpTool(namespaceId, mcpServerId, currentVersion, toolSpecification);
+            toolOperationService.refreshMcpTool(namespaceId, serverSpecification, toolSpecification);
             serverSpecification.getCapabilities().add(McpCapability.TOOL);
-            serverSpecification.setToolsDescriptionRef(mcpServerId + "-" + currentVersion + Constants.MCP_SERVER_TOOL_DATA_ID_SUFFIX);
+            String version = serverSpecification.getVersionDetail().getVersion();
+            String toolSpecDataId = McpConfigUtils.formatServerToolSpecDataId(mcpServerId, version);
+            serverSpecification.setToolsDescriptionRef(toolSpecDataId);
         }
         if (null != endpointSpecification) {
             Service service = endpointOperationService.createMcpServerEndpointServiceIfNecessary(namespaceId, mcpServerId,
@@ -436,26 +466,23 @@ private ConfigFormV3 buildMcpServerVersionForm(String namespaceId, McpServerVers
         configFormV3.setGroupName(Constants.MCP_SERVER_VERSIONS_GROUP);
         configFormV3.setGroup(Constants.MCP_SERVER_VERSIONS_GROUP);
         configFormV3.setNamespaceId(namespaceId);
-        configFormV3.setDataId(mcpServerVersionInfo.getId() + Constants.MCP_SERVER_VERSION_DATA_ID_SUFFIX);
+        configFormV3.setDataId(McpConfigUtils.formatServerVersionInfoDataId(mcpServerVersionInfo.getId()));
         configFormV3.setContent(JacksonUtils.toJson(mcpServerVersionInfo));
         configFormV3.setType(ConfigType.JSON.getType());
         configFormV3.setAppName(mcpServerVersionInfo.getName());
         configFormV3.setSrcUser("nacos");
-        configFormV3.setConfigTags(buildMcpServerVersionConfigTags(mcpServerVersionInfo.getName()));
+        String configTags = buildMcpServerVersionConfigTags(mcpServerVersionInfo.getName());
+        configFormV3.setConfigTags(configTags);
         return configFormV3;
     }
     
-    private String buildMcpServerVersionConfigTags(String serverName) {
-        return StringUtils.join(Arrays.asList(MCP_SERVER_CONFIG_MARK, Constants.MCP_SERVER_NAME_TAG_KEY_PREFIX + serverName), ",");
-    }
-    
     private ConfigFormV3 buildMcpConfigForm(String namespaceId, String mcpServerId, String version,
             McpServerBasicInfo serverSpecification) {
         ConfigFormV3 configFormV3 = new ConfigFormV3();
         configFormV3.setGroupName(Constants.MCP_SERVER_GROUP);
         configFormV3.setGroup(Constants.MCP_SERVER_GROUP);
         configFormV3.setNamespaceId(namespaceId);
-        configFormV3.setDataId(mcpServerId + "-" + version + Constants.MCP_SERVER_SPEC_DATA_ID_SUFFIX);
+        configFormV3.setDataId(McpConfigUtils.formatServerSpecInfoDataId(mcpServerId, version));
         configFormV3.setContent(JacksonUtils.toJson(serverSpecification));
         configFormV3.setType(ConfigType.JSON.getType());
         configFormV3.setAppName(serverSpecification.getName());
@@ -466,7 +493,7 @@ private ConfigFormV3 buildMcpConfigForm(String namespaceId, String mcpServerId,
     
     private ConfigQueryChainRequest buildQueryMcpServerRequest(String namespaceId, String mcpServerId, String version) {
         ConfigQueryChainRequest request = new ConfigQueryChainRequest();
-        request.setDataId(mcpServerId + "-" + version + Constants.MCP_SERVER_SPEC_DATA_ID_SUFFIX);
+        request.setDataId(McpConfigUtils.formatServerSpecInfoDataId(mcpServerId, version));
         request.setGroup(Constants.MCP_SERVER_GROUP);
         request.setTenant(namespaceId);
         return request;
@@ -474,7 +501,7 @@ private ConfigQueryChainRequest buildQueryMcpServerRequest(String namespaceId, S
     
     private ConfigQueryChainRequest buildQueryMcpServerVersionInfoRequest(String namespaceId, String mcpServerId) {
         ConfigQueryChainRequest request = new ConfigQueryChainRequest();
-        request.setDataId(mcpServerId + Constants.MCP_SERVER_VERSION_DATA_ID_SUFFIX);
+        request.setDataId(McpConfigUtils.formatServerVersionInfoDataId(mcpServerId));
         request.setGroup(Constants.MCP_SERVER_VERSIONS_GROUP);
         request.setTenant(namespaceId);
         return request;
@@ -485,10 +512,14 @@ private McpServerVersionInfo transferToMcpServerVersionInfo(String content) {
         String latestPublishedVersion = versionInfo.getLatestPublishedVersion();
         for (ServerVersionDetail versionDetail : versionInfo.getVersionDetails()) {
             if (versionDetail.getVersion().equals(latestPublishedVersion)) {
+                versionDetail.setIs_latest(true);
                 versionInfo.setVersionDetail(versionDetail);
                 break;
+            } else {
+                versionDetail.setIs_latest(false);
             }
         }
+        versionInfo.setVersion(latestPublishedVersion);
         return versionInfo;
     }
     
@@ -504,4 +535,12 @@ private String resolveMcpServerId(String namespaceId, String serverName, String
         
         return null;
     }
+    
+    private void checkMcpServerIndex(String mcpServerId) throws NacosApiException {
+        McpServerIndexData indexData = mcpServerIndex.getMcpServerById(mcpServerId);
+        if (Objects.isNull(indexData)) {
+            throw new NacosApiException(NacosApiException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
+                    String.format("mcp server `%s` not found", mcpServerId));
+        }
+    }
 }
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/service/McpToolOperationService.java b/ai/src/main/java/com/alibaba/nacos/ai/service/McpToolOperationService.java
index 6fc68265112..f300aac4c4e 100644
--- a/ai/src/main/java/com/alibaba/nacos/ai/service/McpToolOperationService.java
+++ b/ai/src/main/java/com/alibaba/nacos/ai/service/McpToolOperationService.java
@@ -17,6 +17,8 @@
 package com.alibaba.nacos.ai.service;
 
 import com.alibaba.nacos.ai.constant.Constants;
+import com.alibaba.nacos.ai.utils.McpConfigUtils;
+import com.alibaba.nacos.api.ai.model.mcp.McpServerBasicInfo;
 import com.alibaba.nacos.api.ai.model.mcp.McpTool;
 import com.alibaba.nacos.api.ai.model.mcp.McpToolSpecification;
 import com.alibaba.nacos.api.config.ConfigType;
@@ -56,14 +58,15 @@ public McpToolOperationService(ConfigQueryChainService configQueryChainService,
      * @param toolSpecification mcp server included tools, see {@link McpTool}, optional
      * @throws NacosException any exception during handling
      */
-    public void refreshMcpTool(String namespaceId, String mcpServerId, String version, McpToolSpecification toolSpecification)
+    public void refreshMcpTool(String namespaceId, McpServerBasicInfo serverBasicInfo, 
+                               McpToolSpecification toolSpecification)
             throws NacosException {
         ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
-        configOperationService.publishConfig(buildMcpToolConfigForm(namespaceId, mcpServerId, version, toolSpecification),
-                configRequestInfo, null);
+        ConfigFormV3 toolConfigForm = buildMcpToolConfigForm(namespaceId, serverBasicInfo, toolSpecification);
+        configOperationService.publishConfig(toolConfigForm, configRequestInfo, null);
     }
     
-    public McpToolSpecification getMcpTool(String namespaceId, String toolsDescriptionRef) throws NacosException {
+    public McpToolSpecification getMcpTool(String namespaceId, String toolsDescriptionRef) {
         ConfigQueryChainRequest request = buildQueryMcpToolRequest(namespaceId, toolsDescriptionRef);
         ConfigQueryChainResponse response = configQueryChainService.handle(request);
         if (ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND == response.getStatus()) {
@@ -73,20 +76,24 @@ public McpToolSpecification getMcpTool(String namespaceId, String toolsDescripti
     }
     
     public void deleteMcpTool(String namespaceId, String mcpServerId, String version) throws NacosException {
-        configOperationService.deleteConfig(mcpServerId + "-" + version + Constants.MCP_SERVER_TOOL_DATA_ID_SUFFIX,
+        configOperationService.deleteConfig(McpConfigUtils.formatServerToolSpecDataId(mcpServerId, version),
                 Constants.MCP_SERVER_TOOL_GROUP, namespaceId, null, null, "nacos", null);
     }
     
-    private ConfigFormV3 buildMcpToolConfigForm(String namespaceId, String mcpServerId, String version, 
+    private ConfigFormV3 buildMcpToolConfigForm(String namespaceId, McpServerBasicInfo mcpServerBasicInfo, 
                                                 McpToolSpecification toolSpecification) {
         ConfigFormV3 configFormV3 = new ConfigFormV3();
         configFormV3.setGroupName(Constants.MCP_SERVER_TOOL_GROUP);
         configFormV3.setGroup(Constants.MCP_SERVER_TOOL_GROUP);
         configFormV3.setNamespaceId(namespaceId);
-        configFormV3.setDataId(mcpServerId + "-" + version + Constants.MCP_SERVER_TOOL_DATA_ID_SUFFIX);
+
+        String toolSpecDataId = McpConfigUtils.formatServerToolSpecDataId(mcpServerBasicInfo.getId(), 
+                mcpServerBasicInfo.getVersionDetail().getVersion());
+        configFormV3.setDataId(toolSpecDataId);
+        
         configFormV3.setContent(JacksonUtils.toJson(toolSpecification));
         configFormV3.setType(ConfigType.JSON.getType());
-        configFormV3.setAppName(mcpServerId);
+        configFormV3.setAppName(mcpServerBasicInfo.getName());
         configFormV3.setSrcUser("nacos");
         configFormV3.setConfigTags(Constants.MCP_SERVER_CONFIG_MARK);
         return configFormV3;
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/utils/McpConfigUtils.java b/ai/src/main/java/com/alibaba/nacos/ai/utils/McpConfigUtils.java
new file mode 100644
index 00000000000..e43331e96a8
--- /dev/null
+++ b/ai/src/main/java/com/alibaba/nacos/ai/utils/McpConfigUtils.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999-2024 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.nacos.ai.utils;
+
+import com.alibaba.nacos.ai.constant.Constants;
+import com.alibaba.nacos.common.utils.StringUtils;
+import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainResponse;
+
+import java.util.Arrays;
+
+import static com.alibaba.nacos.ai.constant.Constants.MCP_SERVER_CONFIG_MARK;
+
+/**
+ * Mcp config utils.
+ * @author xinluo
+ */
+public class McpConfigUtils {
+
+    /**
+     * Format the Mcp server version info config data id.
+     * @param id server id
+     * @return mcp server version info config data id
+     */
+    public static String formatServerVersionInfoDataId(String id) {
+        return String.format(Constants.SERVER_VERSION_CONFIG_DATA_ID_TEMPLATE, id);
+    }
+    
+    public static String formatServerSpecInfoDataId(String id, String version) {
+        return String.format(Constants.SERVER_SPECIFICATION_CONFIG_DATA_ID_TEMPLATE, id, version);
+    }
+    
+    public static String formatServerToolSpecDataId(String id, String version) {
+        return String.format(Constants.SERVER_TOOLS_SPEC_CONFIG_DATA_ID_TEMPLATE, id, version);
+    }
+    
+    public static String formatServerNameTagBlurSearchValue(String serverName) {
+        return Constants.MCP_SERVER_NAME_TAG_KEY_PREFIX + Constants.ALL_PATTERN + serverName + Constants.ALL_PATTERN;
+    }
+    
+    public static String formatServerNameTagAccurateSearchValue(String serverName) {
+        return Constants.MCP_SERVER_NAME_TAG_KEY_PREFIX +  serverName;
+    }
+    
+    public static boolean isConfigFound(ConfigQueryChainResponse.ConfigQueryStatus status) {
+        return ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_FOUND_FORMAL.equals(status);
+    }
+    
+    public static boolean isConfigNotFound(ConfigQueryChainResponse.ConfigQueryStatus status) {
+        return ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND.equals(status);
+    }
+
+    public static String buildMcpServerVersionConfigTags(String serverName) {
+        return StringUtils.join(Arrays.asList(MCP_SERVER_CONFIG_MARK, Constants.MCP_SERVER_NAME_TAG_KEY_PREFIX + serverName), ",");
+    }
+}
diff --git a/ai/src/main/java/com/alibaba/nacos/ai/utils/McpProtocolUtils.java b/ai/src/main/java/com/alibaba/nacos/ai/utils/McpProtocolUtils.java
new file mode 100644
index 00000000000..f09d3920f2e
--- /dev/null
+++ b/ai/src/main/java/com/alibaba/nacos/ai/utils/McpProtocolUtils.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2024 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.nacos.ai.utils;
+
+import com.alibaba.nacos.ai.constant.Constants;
+
+/**
+ * Mcp protocol related utils.
+ * @author xinluo 
+ */
+public class McpProtocolUtils {
+    
+    public static boolean isProtocolNeedTranslator(String protocol) {
+        return Constants.PROTOCOL_TYPE_HTTP.equals(protocol) || Constants.PROTOCOL_TYPE_HTTPS.equals(protocol);
+    }
+}
diff --git a/api/src/main/java/com/alibaba/nacos/api/ai/model/mcp/McpServerBasicInfo.java b/api/src/main/java/com/alibaba/nacos/api/ai/model/mcp/McpServerBasicInfo.java
index ad822649cbb..0282742d7ca 100644
--- a/api/src/main/java/com/alibaba/nacos/api/ai/model/mcp/McpServerBasicInfo.java
+++ b/api/src/main/java/com/alibaba/nacos/api/ai/model/mcp/McpServerBasicInfo.java
@@ -48,6 +48,8 @@ public class McpServerBasicInfo {
     
     private ServerVersionDetail versionDetail;
     
+    private String version;
+    
     /**
      * Should be set when `type` is not {@link AiConstants.Mcp#MCP_PROTOCOL_STDIO}.
      */
@@ -152,4 +154,12 @@ public Repository getRepository() {
     public void setRepository(Repository repository) {
         this.repository = repository;
     }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
 }
diff --git a/console-ui/src/pages/AI/McpDetail/CreateTools/index.js b/console-ui/src/pages/AI/McpDetail/CreateTools/index.js
index c49e9944912..4a01fc42670 100644
--- a/console-ui/src/pages/AI/McpDetail/CreateTools/index.js
+++ b/console-ui/src/pages/AI/McpDetail/CreateTools/index.js
@@ -485,7 +485,7 @@ const CreateTools = React.forwardRef((props, ref) => {
           onClose={closeDialog}
           style={{ width: '70%' }}
         >
-          <Form field={field} {...formitemLayout} isPreview={isPreview}>
+          <Form field={field} {...formitemLayout}>
             {/* 名称 */}
             <Form.Item label={locale.toolName} required isPreview={!!type}>
               <Input
diff --git a/console-ui/src/pages/AI/McpDetail/McpDetail.js b/console-ui/src/pages/AI/McpDetail/McpDetail.js
index b423906ec36..cab9b03f1ac 100644
--- a/console-ui/src/pages/AI/McpDetail/McpDetail.js
+++ b/console-ui/src/pages/AI/McpDetail/McpDetail.js
@@ -143,7 +143,7 @@ class McpDetail extends React.Component {
     const endpoints = [];
     for (let i = 0; i < this.state?.serverConfig?.backendEndpoints?.length; i++) {
       const item = this.state?.serverConfig?.backendEndpoints[i];
-      const endpoint = item.address + item.port + item.path;
+      const endpoint = item.address + ':' + item.port + item.path;
       const serverConfig = {
         index: i,
         endpoint: endpoint,
diff --git a/console-ui/src/pages/AI/NewMcpServer/NewMcpServer.js b/console-ui/src/pages/AI/NewMcpServer/NewMcpServer.js
index afdd23d703b..f011618d80a 100644
--- a/console-ui/src/pages/AI/NewMcpServer/NewMcpServer.js
+++ b/console-ui/src/pages/AI/NewMcpServer/NewMcpServer.js
@@ -129,9 +129,7 @@ class NewMcpServer extends React.Component {
           versionsList: allPublishedVersions,
         });
 
-        if (localServerConfig && JSON.stringify(localServerConfig, null, 2) !== '{}') {
-          initFileData['localServerConfig'] = JSON.stringify(localServerConfig, null, 2);
-        }
+        initFileData['localServerConfig'] = JSON.stringify(localServerConfig, null, 2);
 
         if (remoteServerConfig) {
           initFileData['exportPath'] = remoteServerConfig?.exportPath;
diff --git a/maintainer-client/src/main/java/com/alibaba/nacos/maintainer/client/ai/McpMaintainerService.java b/maintainer-client/src/main/java/com/alibaba/nacos/maintainer/client/ai/McpMaintainerService.java
index 0b74c77039e..b542253cf9a 100644
--- a/maintainer-client/src/main/java/com/alibaba/nacos/maintainer/client/ai/McpMaintainerService.java
+++ b/maintainer-client/src/main/java/com/alibaba/nacos/maintainer/client/ai/McpMaintainerService.java
@@ -69,7 +69,7 @@ default Page<McpServerBasicInfo> listMcpServer(int pageNo, int pageSize) throws
      * @throws NacosException if fail to list mcp server
      */
     default Page<McpServerBasicInfo> listMcpServer(String mcpName, int pageNo, int pageSize) throws NacosException {
-        return listMcpServer("", mcpName, pageNo, pageSize);
+        return listMcpServer("public", mcpName, pageNo, pageSize);
     }
 
     /**


Reviews:
user: login: lingma-agents[bot]
body: ## 🔍 代码评审报告

### 🎯 评审意见概览

| 严重度 | 数量 | 说明 |
|:---|:---:|:---|
| 🔴 **Blocker** | 0 | 阻断性问题，需立即修复。例如：系统崩溃、关键功能不可用或严重安全漏洞。 |
| 🟠 **Critical** | 1 | 严重问题，高优先级修复。例如：核心功能异常或性能瓶颈影响用户体验。 |
| 🟡 **Major** | 2 | 主要问题，建议修复。例如：非核心功能缺陷或代码维护性较差。 |
| 🟢 **Minor** | 2 | 次要问题，酌情优化。例如：代码格式不规范或注释缺失。 |

**总计：** 5 个问题

---

## 📋 评审意见详情

### 💡 单文件建议

<blockquote>
以下是文件级别的代码建议，聚焦于代码的可读性、可维护性和潜在问题。
</blockquote>

<details>
<summary>☕ ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpUpdateForm.java (1 💬)</summary>

<ul>
<li><a href="https://github.com/alibaba/nacos/pull/13424#discussion_r2103877355">修改 `latest` 字段类型可能破坏原有空值检查逻辑</a> (L31)</li>
</ul>
</details>

<details>
<summary>☕ ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java (2 💬)</summary>

<ul>
<li><a href="https://github.com/alibaba/nacos/pull/13424#discussion_r2103877358">分页逻辑中 `remains` 计算存在潜在越界风险</a> (L99-L100)</li>
<li><a href="https://github.com/alibaba/nacos/pull/13424#discussion_r2103877360">搜索逻辑中 `searchedItemsCount` 累加存在计算错误</a> (L120)</li>
</ul>
</details>

<details>
<summary>📜 console-ui/src/pages/AI/NewMcpServer/NewMcpServer.js (1 💬)</summary>

<ul>
<li><a href="https://github.com/alibaba/nacos/pull/13424#discussion_r2103877361">initFileData赋值可能导致存储空配置</a> (L132)</li>
</ul>
</details>

<details>
<summary>☕ maintainer-client/src/main/java/com/alibaba/nacos/maintainer/client/ai/McpMaintainerService.java (1 💬)</summary>

<ul>
<li><a href="https://github.com/alibaba/nacos/pull/13424#discussion_r2103877364">listMcpServer默认参数修改未更新文档</a> (L72)</li>
</ul>
</details>

### 🚀 跨文件建议

<blockquote>
以下是对代码架构和设计的综合分析，聚焦于跨文件交互、系统一致性和潜在优化空间。
</blockquote>

<details>
<summary>🔍 <strong>1. 数据ID生成逻辑不统一可能导致配置检索失败</strong></summary>

新增McpConfigUtils工具类封装了数据ID的格式化方法，但部分旧代码仍使用硬编码的字符串拼接方式，可能导致配置数据ID不一致。例如在McpToolOperationService.java的buildMcpToolConfigForm方法中，虽然改用formatServerToolSpecDataId方法生成dataId，但在其他场景如deleteMcpTool方法中仍存在旧拼接方式。若未全面替换，将导致配置存储和检索路径不匹配。

**📌 关键代码：**
-  [`ai/src/main/java/com/alibaba/nacos/ai/service/McpToolOperationService.java` (78-80)](https://github.com/alibaba/nacos/blob/fix-ai-api-bugs/ai/src/main/java/com/alibaba/nacos/ai/service/McpToolOperationService.java#L78-L80)
```java
configOperationService.deleteConfig(McpConfigUtils.formatServerToolSpecDataId(mcpServerId, version),
    Constants.MCP_SERVER_TOOL_GROUP, namespaceId, null, null, "nacos", null);
```

-  [`ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java` (399-400)](https://github.com/alibaba/nacos/blob/fix-ai-api-bugs/ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java#L399-L400)
```java
String serverSpecDataId = McpConfigUtils.formatServerSpecInfoDataId(mcpServerId, versionNeedDelete);
```

**⚠️ 潜在风险：** 数据ID生成方式不统一将导致配置存储路径与检索路径不匹配，引发"配置未找到"错误，影响服务器管理功能正常运行。

</details>

<details>
<summary>🔍 <strong>2. 协议类型处理未覆盖HTTPS场景</strong></summary>

新增PROTOCOL_TYPE_HTTPS常量后，McpProtocolUtils的isProtocolNeedTranslator方法仅检查HTTP类型，未包含HTTPS。在injectBackendEndpointRef方法中，当协议类型为HTTPS时将无法触发翻译器地址注入，导致非STDIO协议的服务器端点配置失效。

**📌 关键代码：**
-  [`ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java` (249-251)](https://github.com/alibaba/nacos/blob/fix-ai-api-bugs/ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java#L249-L251)
```java
if (McpProtocolUtils.isProtocolNeedTranslator(detailInfo.getProtocol())) {
    // translator logic
}
```

-  [`ai/src/main/java/com/alibaba/nacos/ai/utils/McpProtocolUtils.java` (27-28)](https://github.com/alibaba/nacos/blob/fix-ai-api-bugs/ai/src/main/java/com/alibaba/nacos/ai/utils/McpProtocolUtils.java#L27-L28)
```java
public static boolean isProtocolNeedTranslator(String protocol) {
    return Constants.PROTOCOL_TYPE_HTTP.equals(protocol);
}
```

**⚠️ 潜在风险：** HTTPS协议未被正确识别将导致后端服务端点无法正确注入，影响非STDIO协议服务器的调用链路建立。

</details>

<details>
<summary>🔍 <strong>3. 分页逻辑中的数据转换存在空指针风险</strong></summary>

在McpServerOperationService.java的mapIndexToBasicServerInfo方法中，当indexData为空时finalResult初始化为Collections.emptyList()，但在流式处理时若indexData.getPageItems()为null将抛出空指针异常。该方法未对indexData.getPageItems()进行空值检查，而旧版本代码存在类似问题未被完全修正。

**📌 关键代码：**
-  [`ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java` (132-134)](https://github.com/alibaba/nacos/blob/fix-ai-api-bugs/ai/src/main/java/com/alibaba/nacos/ai/service/McpServerOperationService.java#L132-L134)
```java
List<McpServerBasicInfo> finalResult = Collections.emptyList();
if (CollectionUtils.isNotEmpty(indexData.getPageItems())) {
    finalResult = indexData.getPageItems().stream()...
```

**⚠️ 潜在风险：** 空指针异常将导致分页接口崩溃，影响服务器列表查询功能。

</details>

<details>
<summary>🔍 <strong>4. MCP服务器名称字段移除导致搜索逻辑失效</strong></summary>

McpServerIndexData.java移除了name字段，但searchMcpServers方法中仍依赖原始name值进行模糊搜索。例如在旧代码中使用"config_tags"字段存储名称标签，新代码虽改用McpConfigUtils.formatServerNameTagBlurSearchValue，但未确保所有搜索场景正确传递name参数，可能导致搜索结果不准确。

**📌 关键代码：**
-  [`ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java` (154-157)](https://github.com/alibaba/nacos/blob/fix-ai-api-bugs/ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java#L154-L157)
```java
if (Constants.MCP_LIST_SEARCH_BLUR.equals(search) || StringUtils.isEmpty(serverName)) {
    nameTag = McpConfigUtils.formatServerNameTagBlurSearchValue(serverName);
}
```

**⚠️ 潜在风险：** 名称字段缺失将导致基于名称的模糊搜索失效，影响服务器管理界面的搜索功能。

</details>

<details>
<summary>🔍 <strong>5. 新增工具类未被充分测试</strong></summary>

新增的McpConfigUtils和McpProtocolUtils工具类未在单元测试中覆盖核心方法，如formatServerVersionInfoDataId、isProtocolNeedTranslator等。现有测试用例未验证数据ID生成逻辑和协议类型判断的正确性，可能导致生产环境出现配置路径错误或协议类型误判。

**⚠️ 潜在风险：** 缺乏测试覆盖将导致工具类核心功能存在隐蔽缺陷，引发配置管理模块的连锁故障。

</details>

---

<details>
<summary><strong>💡 小贴士</strong></summary>

### 与 lingma-agents 交流的方式

**📜 直接回复评论**
直接回复本条评论，lingma-agents 将自动处理您的请求。例如：

- _在当前代码中添加详细的注释说明。_

- _请详细介绍一下你说的 LRU 改造方案，并使用伪代码加以说明。_

**📜 在代码行处标记**
在文件的特定位置创建评论并 @lingma-agents。例如：
- _@Lingma-Agent 分析这个方法的性能瓶颈并提供优化建议。_

- _@Lingma-Agent 对这个方法生成优化代码。_

**📜 在讨论中提问**
在任何讨论中 @lingma-agents 来获取帮助。例如：
- _@Lingma-Agent 请总结上述讨论并提出解决方案。_

- _@Lingma-Agent 请根据讨论内容生成优化代码。_

</details>

state: COMMENTED
author_association: NONE
submitted_at: 2025-05-23T06:14:01Z
user: login: KomachiSion
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-23T06:32:42Z

Review comments:
diff_hunk: @@ -28,7 +28,7 @@ public class McpUpdateForm extends McpDetailForm {
     @Serial
     private static final long serialVersionUID = 4144251088520249913L;
     
-    private Boolean latest;
+    private boolean latest = true;
path: ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpUpdateForm.java
user: login: lingma-agents[bot]
body: **修改 `latest` 字段类型可能破坏原有空值检查逻辑**

> 🟠 **Critical** | 🐞 **Bugs**

### 📋 问题详情

将 `latest` 字段从 `Boolean` 改为 `boolean` 并初始化为 `true`，可能导致原有空值校验失效。由于 `boolean` 是原始类型无法为 `null`，而原 `Boolean` 类型允许空值，此变更可能影响依赖空值判断的业务逻辑（例如前端传参为 `null` 时的处理）。

### 💡 解决方案

将字段类型恢复为 `Boolean` 并保持默认值为 `true`，以兼容空值判断场景：
```diff
- private boolean latest = true;
+ private Boolean latest = true;
```




---

> 您的反馈对我们很重要！(建议右键在新标签页中打开以下链接)

  [有用意见👍](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-d33d75c18006&feedback_type=helpful) ｜ [无用意见👎](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-d33d75c18006&feedback_type=neutral) ｜ [错误意见❌](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-d33d75c18006&feedback_type=misleading)



<!-- This is an auto-generated comment by LingmaAgent -->


created_at: 2025-05-23T06:14:00Z
author_association: NONE
diff_hunk: @@ -78,33 +80,44 @@ public Page<McpServerIndexData> searchMcpServerByName(String namespaceId, String
                                                           String search, int offset, int limit) {
         List<String> namespaceIdList;
         if (StringUtils.isEmpty(namespaceId)) {
-            namespaceIdList = getNamespaceList();
+            namespaceIdList = fetchOrderedNamespaceList();
         } else {
             namespaceIdList = Collections.singletonList(namespaceId);
         }
         
-        int searchedItemsCount = 0;
         int totalCount = 0;
         int remains = limit;
+        int searchedItemsCount = 0;
         List<McpServerIndexData> result = new ArrayList<>();
         
-        for (String nsId : namespaceIdList) {
-            Page<ConfigInfo> countInfo = searchMcpServers(nsId, name, search, 1);
-            if (offset >= searchedItemsCount && offset <= searchedItemsCount + countInfo.getTotalCount()) {
-                Page<ConfigInfo> pageConfigs = searchMcpServers(nsId, name, search, 
-                        offset - searchedItemsCount + remains);
-                List<McpServerIndexData> indexDataList = pageConfigs.getPageItems()
-                        .stream().skip(offset - searchedItemsCount)
-                        .map(this::mapMcpServerVersionConfigToIndexData).toList();
-                result.addAll(indexDataList);
+        for (String ns : namespaceIdList) {
+            Page<ConfigInfo> countInfo = searchMcpServers(ns, name, search, 1);
+            int totalServerInNs = countInfo.getTotalCount();
+            
+            // find the first namespace which match the offset.
+            if (offset >= searchedItemsCount && offset <= searchedItemsCount + totalServerInNs) {
+                int currentSearchLimit = offset - searchedItemsCount + remains;
+                Page<ConfigInfo> serverInfos = searchMcpServers(ns, name, search, currentSearchLimit);
path: ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java
user: login: lingma-agents[bot]
body: **分页逻辑中 `remains` 计算存在潜在越界风险**

> 🟡 **Major** | 🧹 **Code Smells**

### 📋 问题详情

在 `searchMcpServerByName` 方法中，`currentSearchLimit` 的计算公式 `offset - searchedItemsCount + remains` 可能导致负数或过大值，引发接口参数校验失败或性能问题。

### 💡 解决方案

添加边界值保护防止无效参数：
```diff
- int currentSearchLimit = offset - searchedItemsCount + remains;
+ int currentSearchLimit = Math.max(1, offset - searchedItemsCount + remains);
```




---

> 您的反馈对我们很重要！(建议右键在新标签页中打开以下链接)

  [有用意见👍](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-040abbc3f2b7&feedback_type=helpful) ｜ [无用意见👎](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-040abbc3f2b7&feedback_type=neutral) ｜ [错误意见❌](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-040abbc3f2b7&feedback_type=misleading)



<!-- This is an auto-generated comment by LingmaAgent -->


created_at: 2025-05-23T06:14:00Z
author_association: NONE
diff_hunk: @@ -78,33 +80,44 @@ public Page<McpServerIndexData> searchMcpServerByName(String namespaceId, String
                                                           String search, int offset, int limit) {
         List<String> namespaceIdList;
         if (StringUtils.isEmpty(namespaceId)) {
-            namespaceIdList = getNamespaceList();
+            namespaceIdList = fetchOrderedNamespaceList();
         } else {
             namespaceIdList = Collections.singletonList(namespaceId);
         }
         
-        int searchedItemsCount = 0;
         int totalCount = 0;
         int remains = limit;
+        int searchedItemsCount = 0;
         List<McpServerIndexData> result = new ArrayList<>();
         
-        for (String nsId : namespaceIdList) {
-            Page<ConfigInfo> countInfo = searchMcpServers(nsId, name, search, 1);
-            if (offset >= searchedItemsCount && offset <= searchedItemsCount + countInfo.getTotalCount()) {
-                Page<ConfigInfo> pageConfigs = searchMcpServers(nsId, name, search, 
-                        offset - searchedItemsCount + remains);
-                List<McpServerIndexData> indexDataList = pageConfigs.getPageItems()
-                        .stream().skip(offset - searchedItemsCount)
-                        .map(this::mapMcpServerVersionConfigToIndexData).toList();
-                result.addAll(indexDataList);
+        for (String ns : namespaceIdList) {
+            Page<ConfigInfo> countInfo = searchMcpServers(ns, name, search, 1);
+            int totalServerInNs = countInfo.getTotalCount();
+            
+            // find the first namespace which match the offset.
+            if (offset >= searchedItemsCount && offset <= searchedItemsCount + totalServerInNs) {
+                int currentSearchLimit = offset - searchedItemsCount + remains;
+                Page<ConfigInfo> serverInfos = searchMcpServers(ns, name, search, currentSearchLimit);
+                if (CollectionUtils.isEmpty(serverInfos.getPageItems())) {
+                    continue;
+                }
+                
+                List<McpServerIndexData> indexDataList = serverInfos.getPageItems()
+                        .stream()
+                        .skip(offset - searchedItemsCount)
+                        .map(this::mapMcpServerVersionConfigToIndexData)
+                        .toList();
                 remains -= indexDataList.size();
+                result.addAll(indexDataList);
             } else if (remains > 0 && remains < limit) {
-                Page<ConfigInfo> pageConfigs = searchMcpServers(nsId, name, search, remains);
-                remains -= pageConfigs.getPageItems().size();
+                Page<ConfigInfo> pageConfigs = searchMcpServers(ns, name, search, remains);
                 List<McpServerIndexData> indexDataList = pageConfigs.getPageItems().stream()
-                        .map(this::mapMcpServerVersionConfigToIndexData).toList();
+                        .map(this::mapMcpServerVersionConfigToIndexData)
+                        .toList();
+                remains -= pageConfigs.getPageItems().size();
                 result.addAll(indexDataList);
             }
+            
path: ai/src/main/java/com/alibaba/nacos/ai/index/PlainMcpServerIndex.java
user: login: lingma-agents[bot]
body: **搜索逻辑中 `searchedItemsCount` 累加存在计算错误**

> 🟡 **Major** | 🐞 **Bugs**

### 📋 问题详情

在 `searchMcpServerByName` 方法中，`searchedItemsCount` 累加时使用了 `countInfo.getPageItems().size()`。由于 `countInfo` 是通过 `searchMcpServers` 方法（limit=1）获取的，其 `pageItems` 大小始终为 1，导致实际已处理条目数统计错误，可能引发分页结果不准确。

### 💡 解决方案

应使用 `countInfo.getTotalCount()` 替代 `pageItems.size()` 进行累加：
```diff
- searchedItemsCount += countInfo.getPageItems().size();
+ searchedItemsCount += countInfo.getTotalCount();
```




---

> 您的反馈对我们很重要！(建议右键在新标签页中打开以下链接)

  [有用意见👍](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-1a328d6b0265&feedback_type=helpful) ｜ [无用意见👎](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-1a328d6b0265&feedback_type=neutral) ｜ [错误意见❌](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-1a328d6b0265&feedback_type=misleading)



<!-- This is an auto-generated comment by LingmaAgent -->


created_at: 2025-05-23T06:14:00Z
author_association: NONE
diff_hunk: @@ -129,9 +129,7 @@ class NewMcpServer extends React.Component {
           versionsList: allPublishedVersions,
         });
 
-        if (localServerConfig && JSON.stringify(localServerConfig, null, 2) !== '{}') {
-          initFileData['localServerConfig'] = JSON.stringify(localServerConfig, null, 2);
-        }
+        initFileData['localServerConfig'] = JSON.stringify(localServerConfig, null, 2);
path: console-ui/src/pages/AI/NewMcpServer/NewMcpServer.js
user: login: lingma-agents[bot]
body: **initFileData赋值可能导致存储空配置**

> 🟢 **Minor** | 🧹 **Code Smells**

### 📋 问题详情

直接赋值initFileData['localServerConfig'] = JSON.stringify(...)，当localServerConfig为空对象时会存储'{}'字符串。建议恢复原条件判断以避免存储无效配置。

### 💡 解决方案

恢复条件判断逻辑：
```diff
+ if (localServerConfig && JSON.stringify(localServerConfig, null, 2) !== '{}') {
+   initFileData['localServerConfig'] = JSON.stringify(localServerConfig, null, 2);
+ }
```




---

> 您的反馈对我们很重要！(建议右键在新标签页中打开以下链接)

  [有用意见👍](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-e94e3bf36651&feedback_type=helpful) ｜ [无用意见👎](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-e94e3bf36651&feedback_type=neutral) ｜ [错误意见❌](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-e94e3bf36651&feedback_type=misleading)



<!-- This is an auto-generated comment by LingmaAgent -->


created_at: 2025-05-23T06:14:00Z
author_association: NONE
diff_hunk: @@ -69,7 +69,7 @@ default Page<McpServerBasicInfo> listMcpServer(int pageNo, int pageSize) throws
      * @throws NacosException if fail to list mcp server
      */
     default Page<McpServerBasicInfo> listMcpServer(String mcpName, int pageNo, int pageSize) throws NacosException {
-        return listMcpServer("", mcpName, pageNo, pageSize);
+        return listMcpServer("public", mcpName, pageNo, pageSize);
path: maintainer-client/src/main/java/com/alibaba/nacos/maintainer/client/ai/McpMaintainerService.java
user: login: lingma-agents[bot]
body: **listMcpServer默认参数修改未更新文档**

> 🟢 **Minor** | 🧹 **Code Smells**

### 📋 问题详情

listMcpServer方法默认参数从空字符串改为'public'，但方法注释未更新说明。可能导致调用者误解默认行为，需要同步更新文档说明。

### 💡 解决方案

更新方法注释：
```diff
@@ -69,7 +69,7 @@
  * @throws NacosException if fail to list mcp server
  */
 default Page<McpServerBasicInfo> listMcpServer(String mcpName, int pageNo, int pageSize) throws NacosException {
-    return listMcpServer("public", mcpName, pageNo, pageSize);
+    return listMcpServer("public", mcpName, pageNo, pageSize); // 默认搜索public仓库
 }
```




---

> 您的反馈对我们很重要！(建议右键在新标签页中打开以下链接)

  [有用意见👍](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-131970847d9b&feedback_type=helpful) ｜ [无用意见👎](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-131970847d9b&feedback_type=neutral) ｜ [错误意见❌](https://ap-southeast-1.lingma-agents-api.aliyuncs.com/v1/code-platform/sessions/s-d0o119cuo6c5b1cg41k0/feedback?suggestion_id=sg-131970847d9b&feedback_type=misleading)



<!-- This is an auto-generated comment by LingmaAgent -->


created_at: 2025-05-23T06:14:00Z
author_association: NONE

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-23T06:07:41Z
body: <!-- thanks-and-hint-to-document: do not delete/edit this line -->
Thanks for your this PR.  :pray: 
Please check again for your PR changes whether contains any usage/api/configuration change such as `Add new API `, `Add new configuration`, `Change default value of configuration`.
If so, please add or update documents(markdown type) in `docs/next/` for repository [nacos-group/nacos-group.github.io](https://github.com/nacos-group/nacos-group.github.io/tree/develop-astro-nacos/src/content/docs/next)

---

感谢您提交的PR。 :pray: 
请再次查看您的PR内容，确认是否包含任何使用方式/API/配置参数的变更，如：`新增API`、`新增配置参数`、`修改默认配置`等操作。
如果是，请确保在提交之前，在仓库[nacos-group/nacos-group.github.io](https://github.com/nacos-group/nacos-group.github.io/tree/develop-astro-nacos/src/content/docs/next)中的`docs/next/`目录下添加或更新文档（markdown格式）。
author_association: NONE
user: login: lingma-agents[bot]
created_at: 2025-05-23T06:08:29Z
body: ### 优化AI MCP服务器管理功能及修复API问题

### 变更文件

<table>
<thead>
<tr>
<th align='left'>文件路径</th>
<th align='left'>变更说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>ai/&#8203;src/&#8203;main/&#8203;java/&#8203;com/&#8203;alibaba/&#8203;nacos/&#8203;ai/&#8203;constant/&#8203;Constants.java</td>
<td>新增HTTPS协议类型常量PROTOCOL_TYPE_HTTPS和ISO标准日期格式RELEASE_DATE_FORMAT，移除废弃的MCP_REGISTRY_PATH配置路径</td>
</tr>
<tr>
<td>ai/&#8203;src/&#8203;main/&#8203;java/&#8203;com/&#8203;alibaba/&#8203;nacos/&#8203;ai/&#8203;form/&#8203;mcp/&#8203;admin/&#8203;McpUpdateForm.java</td>
<td>将latest字段从可空Boolean改为基本类型boolean并设置默认true值，避免空指针异常</td>
</tr>
<tr>
<td>ai/&#8203;src/&#8203;main/&#8203;java/&#8203;com/&#8203;alibaba/&#8203;nacos/&#8203;ai/&#8203;index/&#8203;PlainMcpServerIndex.java</td>
<td>新增有序命名空间排序方法fetchOrderedNamespaceList，重构分页查询逻辑实现跨命名空间高效搜索，引入McpConfigUtils进行搜索参数标准化处理</td>
</tr>
<tr>
<td>ai/&#8203;src/&#8203;main/&#8203;java/&#8203;com/&#8203;alibaba/&#8203;nacos/&#8203;ai/&#8203;service/&#8203;McpServerOperationService.java</td>
<td>新增版本号非空校验和服务器索引检查，重构配置数据生成逻辑使用格式化方法，优化端点注入逻辑并统一配置标签生成</td>
</tr>
<tr>
<td>ai/&#8203;src/&#8203;main/&#8203;java/&#8203;com/&#8203;alibaba/&#8203;nacos/&#8203;ai/&#8203;utils/&#8203;McpConfigUtils.java</td>
<td>新增配置数据ID生成、服务名标签格式化及配置状态判断等工具方法，实现配置相关逻辑的模块化封装</td>
</tr>
<tr>
<td>console-ui/&#8203;src/&#8203;pages/&#8203;AI/&#8203;NewMcpServer/&#8203;NewMcpServer.js</td>
<td>调整本地服务器配置JSON序列化方式，简化文件数据初始化逻辑</td>
</tr>
</tbody>
</table>

### 时序图

```mermaid
sequenceDiagram
    participant McpServerOperationService
    participant McpConfigUtils
    participant ConfigOperationService
    McpServerOperationService->>McpConfigUtils: 调用formatServerVersionInfoDataId生成数据ID
    McpServerOperationService->>ConfigOperationService: 发布版本配置
    McpServerOperationService->>McpConfigUtils: 调用buildMcpServerVersionConfigTags设置标签
    PlainMcpServerIndex->>McpConfigUtils: 调用formatServerNameTagBlurSearchValue处理模糊搜索
    McpProtocolUtils->>Constants: 获取协议类型进行端点注入判断
```

---


<details>
<summary><strong>💡 小贴士</strong></summary>

### 与 lingma-agents 交流的方式

**📜 直接回复评论**
直接回复本条评论，lingma-agents 将自动处理您的请求。例如：

- _在当前代码中添加详细的注释说明。_

- _请详细介绍一下你说的 LRU 改造方案，并使用伪代码加以说明。_

**📜 在代码行处标记**
在文件的特定位置创建评论并 @lingma-agents。例如：
- _@Lingma-Agent 分析这个方法的性能瓶颈并提供优化建议。_

- _@Lingma-Agent 对这个方法生成优化代码。_

**📜 在讨论中提问**
在任何讨论中 @lingma-agents 来获取帮助。例如：
- _@Lingma-Agent 请总结上述讨论并提出解决方案。_

- _@Lingma-Agent 请根据讨论内容生成优化代码。_

</details>



<!-- This is an auto-generated comment by LingmaAgent -->


author_association: NONE
user: login: codecov-commenter
created_at: 2025-05-23T06:30:35Z
body: ## [Codecov](https://app.codecov.io/gh/alibaba/nacos/pull/13424?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) Report
:x: Patch coverage is `25.00000%` with `3 lines` in your changes missing coverage. Please review.
| [Files with missing lines](https://app.codecov.io/gh/alibaba/nacos/pull/13424?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) | Patch % | Lines |
|---|---|---|
| [...aba/nacos/api/ai/model/mcp/McpServerBasicInfo.java](https://app.codecov.io/gh/alibaba/nacos/pull/13424?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba#diff-YXBpL3NyYy9tYWluL2phdmEvY29tL2FsaWJhYmEvbmFjb3MvYXBpL2FpL21vZGVsL21jcC9NY3BTZXJ2ZXJCYXNpY0luZm8uamF2YQ==) | 0.00% | [3 Missing :warning: ](https://app.codecov.io/gh/alibaba/nacos/pull/13424?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alibaba) |

:loudspeaker: Thoughts on this report? [Let us know!](https://github.com/codecov/feedback/issues/255)
author_association: NONE
user: login: wuyfee
created_at: 2025-05-23T06:48:25Z
body: $\color{red}{FAILURE}$
[DETAILS](https://github.com/alibaba/nacos/actions/runs/15203571134)
 ✅ - docker:   success 
 ❌ - deploy (standalone & cluster & standalone_auth):   failure 
 ❌ - e2e-java-test (standalone & cluster & standalone_auth):   skipped 
 ❌ - e2e-go-test (standalone & cluster):   skipped 
 ❌ - e2e-cpp-test (standalone & cluster):   skipped 
 ❌ - e2e-csharp-test (standalone & cluster):   skipped 
 ❌ - e2e-nodejs-test (standalone & cluster):   skipped 
 ❌ - e2e-python-test (standalone & cluster):   skipped 
 ✅ - clean (standalone & cluster & standalone_auth):   success 
author_association: NONE
user: login: wuyfee
created_at: 2025-05-23T06:55:21Z
body: $\color{red}{FAILURE}$
[DETAILS](https://github.com/alibaba/nacos/actions/runs/15203671965)
 ✅ - docker:   success 
 ❌ - deploy (standalone & cluster & standalone_auth):   failure 
 ❌ - e2e-java-test (standalone & cluster & standalone_auth):   skipped 
 ❌ - e2e-go-test (standalone & cluster):   skipped 
 ❌ - e2e-cpp-test (standalone & cluster):   skipped 
 ❌ - e2e-csharp-test (standalone & cluster):   skipped 
 ❌ - e2e-nodejs-test (standalone & cluster):   skipped 
 ❌ - e2e-python-test (standalone & cluster):   skipped 
 ✅ - clean (standalone & cluster & standalone_auth):   success 
author_association: NONE