Compare commits

..

4 Commits
1.0.4 ... main

Author SHA1 Message Date
Sunrisea f24f12c4ba
Support service metadata, update nacos-sdk-python version (#22) 2025-08-08 11:00:09 +08:00
Sunrisea cf9477af7b
Update and optimize log (#19)
* update log

* version 1.0.8
2025-07-29 12:00:01 +08:00
Sunrisea 5ab63b71cd
version 1.0.7, update nacos-maintainer-sdk-python to 0.1.2 (#17)
* Fix bug

* version 1.0.7, update nacos-maintainer-sdk-python to 0.1.2
2025-07-17 21:04:52 +08:00
Sunrisea 291949b579
optimize register logic (#16) 2025-07-17 20:11:42 +08:00
4 changed files with 63 additions and 38 deletions

View File

@ -3,6 +3,7 @@ import json
import logging import logging
from contextlib import AbstractAsyncContextManager from contextlib import AbstractAsyncContextManager
from typing import Literal, Callable, Any from typing import Literal, Callable, Any
from importlib import metadata
import jsonref import jsonref
from maintainer.ai.model.nacos_mcp_info import McpToolMeta, McpServerDetailInfo, \ from maintainer.ai.model.nacos_mcp_info import McpToolMeta, McpServerDetailInfo, \
@ -188,29 +189,30 @@ class NacosServer(Server):
return True return True
def check_compatible(self,server_detail_info:McpServerDetailInfo) -> bool: def check_compatible(self,server_detail_info:McpServerDetailInfo) -> (bool,str):
if server_detail_info.version != self.version: if server_detail_info.version != self.version:
return False return False, f"version not compatible, local version:{self.version}, remote version:{server_detail_info.version}"
if server_detail_info.protocol != self.type: if server_detail_info.protocol != self.type:
return False return False, f"protocol not compatible, local protocol:{self.type}, remote protocol:{server_detail_info.protocol}"
if types.ListToolsRequest in self.request_handlers: if types.ListToolsRequest in self.request_handlers:
checkToolsResult = self.check_tools_compatible(server_detail_info) checkToolsResult = self.check_tools_compatible(server_detail_info)
if not checkToolsResult: if not checkToolsResult:
return False return False , f"tools not compatible, local tools:{self._tmp_tools}, remote tools:{server_detail_info.toolSpec}"
mcp_service_ref = server_detail_info.remoteServerConfig.serviceRef mcp_service_ref = server_detail_info.remoteServerConfig.serviceRef
if not self.is_service_ref_same(mcp_service_ref): is_same_service,error_msg = self.is_service_ref_same(mcp_service_ref)
return False if not is_same_service:
return False, error_msg
return True return True, ""
def is_service_ref_same(self,mcp_service_ref:McpServiceRef) -> bool: def is_service_ref_same(self,mcp_service_ref:McpServiceRef) -> (bool,str):
if self.get_register_service_name() != mcp_service_ref.serviceName: if self._nacos_settings.SERVICE_NAME is not None and self._nacos_settings.SERVICE_NAME != mcp_service_ref.serviceName:
return False return False, f"service name not compatible, local service name:{self._nacos_settings.SERVICE_NAME}, remote service name:{mcp_service_ref.serviceName}"
if mcp_service_ref.groupName != self._nacos_settings.SERVICE_GROUP: if self._nacos_settings.SERVICE_GROUP is not None and self._nacos_settings.SERVICE_GROUP != mcp_service_ref.groupName:
return False return False, f"group name not compatible, local group name:{self._nacos_settings.SERVICE_GROUP}, remote group name:{mcp_service_ref.groupName}"
if mcp_service_ref.namespaceId != self._nacos_settings.NAMESPACE: if mcp_service_ref.namespaceId != self._nacos_settings.NAMESPACE:
return False return False, f"namespace id not compatible, local namespace id:{self._nacos_settings.NAMESPACE}, remote namespace id:{mcp_service_ref.namespaceId}"
return True return True, ""
def get_register_service_name(self) -> str: def get_register_service_name(self) -> str:
@ -266,25 +268,32 @@ class NacosServer(Server):
self.list_tools()(self._list_tmp_tools) self.list_tools()(self._list_tmp_tools)
if server_detail_info is not None: if server_detail_info is not None:
if not self.check_compatible(server_detail_info): is_compatible, error_msg = self.check_compatible(server_detail_info)
logging.error(f"mcp server info is not compatible,{self.name},version:{self.version}") if not is_compatible:
logging.error(f"mcp server info is not compatible,{self.name},version:{self.version},reason:{error_msg}")
raise NacosException( raise NacosException(
f"mcp server info is not compatible,{self.name},version:{self.version}" f"mcp server info is not compatible,{self.name},version:{self.version},reason:{error_msg}"
) )
if types.ListToolsRequest in self.request_handlers: if types.ListToolsRequest in self.request_handlers:
self.update_tools(server_detail_info) self.update_tools(server_detail_info)
asyncio.create_task(self.subscribe()) asyncio.create_task(self.subscribe())
if self._nacos_settings.SERVICE_REGISTER and (self.type == "mcp-sse" if self._nacos_settings.SERVICE_REGISTER and (self.type == "mcp-sse"
or self.type == "mcp-streamable"): or self.type == "mcp-streamable"):
version = metadata.version('nacos-mcp-wrapper-python')
service_meta_data = {
"source": f"nacos-mcp-wrapper-python-{version}",
**self._nacos_settings.SERVICE_META_DATA}
await self.naming_client.register_instance( await self.naming_client.register_instance(
request=RegisterInstanceParam( request=RegisterInstanceParam(
group_name=self._nacos_settings.SERVICE_GROUP, group_name=server_detail_info.remoteServerConfig.serviceRef.groupName,
service_name=self.get_register_service_name(), service_name=server_detail_info.remoteServerConfig.serviceRef.serviceName,
ip=self._nacos_settings.SERVICE_IP, ip=self._nacos_settings.SERVICE_IP,
port=self._nacos_settings.SERVICE_PORT if self._nacos_settings.SERVICE_PORT else port, port=self._nacos_settings.SERVICE_PORT if self._nacos_settings.SERVICE_PORT else port,
ephemeral=self._nacos_settings.SERVICE_EPHEMERAL, ephemeral=self._nacos_settings.SERVICE_EPHEMERAL,
metadata=service_meta_data
) )
) )
logging.info(f"Register to nacos success,{self.name},version:{self.version}")
return return
mcp_tool_specification = None mcp_tool_specification = None
@ -316,7 +325,7 @@ class NacosServer(Server):
endpoint_spec.type = "REF" endpoint_spec.type = "REF"
data = { data = {
"serviceName": self.get_register_service_name(), "serviceName": self.get_register_service_name(),
"groupName": self._nacos_settings.SERVICE_GROUP, "groupName": "DEFAULT_GROUP" if self._nacos_settings.SERVICE_GROUP is None else self._nacos_settings.SERVICE_GROUP,
"namespaceId": self._nacos_settings.NAMESPACE, "namespaceId": self._nacos_settings.NAMESPACE,
} }
endpoint_spec.data = data endpoint_spec.data = data
@ -326,16 +335,6 @@ class NacosServer(Server):
server_basic_info.remoteServerConfig = remote_server_config_info server_basic_info.remoteServerConfig = remote_server_config_info
server_basic_info.protocol = self.type server_basic_info.protocol = self.type
server_basic_info.frontProtocol = self.type server_basic_info.frontProtocol = self.type
if self._nacos_settings.SERVICE_REGISTER:
await self.naming_client.register_instance(
request=RegisterInstanceParam(
group_name=self._nacos_settings.SERVICE_GROUP,
service_name=self.get_register_service_name(),
ip=self._nacos_settings.SERVICE_IP,
port=self._nacos_settings.SERVICE_PORT if self._nacos_settings.SERVICE_PORT else port,
ephemeral=self._nacos_settings.SERVICE_EPHEMERAL,
)
)
try: try:
await self.mcp_service.create_mcp_server(self._nacos_settings.NAMESPACE, await self.mcp_service.create_mcp_server(self._nacos_settings.NAMESPACE,
self.name, self.name,
@ -343,7 +342,7 @@ class NacosServer(Server):
mcp_tool_specification, mcp_tool_specification,
endpoint_spec) endpoint_spec)
except Exception as e: except Exception as e:
logger.info(f"Failed to create MCP server to Nacos,try to update mcp server") logger.info(f"Found MCP server {self.name} in Nacos,try to update it")
version_detail = None version_detail = None
try: try:
version_detail = await self.mcp_service.get_mcp_server_detail( version_detail = await self.mcp_service.get_mcp_server_detail(
@ -352,15 +351,37 @@ class NacosServer(Server):
self.version self.version
) )
except Exception as e_2: except Exception as e_2:
logger.info(f"Cant found version {self.version} of Mcp server {self.name}") logger.info(f" Version {self.version} of Mcp server {self.name} is not in Nacos, try to update it")
if version_detail is None: if version_detail is None:
await self.mcp_service.update_mcp_server( await self.mcp_service.update_mcp_server(
self._nacos_settings.NAMESPACE, self._nacos_settings.NAMESPACE,
self.name, self.name,
False, True,
server_basic_info, server_basic_info,
mcp_tool_specification, mcp_tool_specification,
endpoint_spec endpoint_spec
) )
else:
_is_compatible,error_msg = self.check_compatible(version_detail)
if not _is_compatible:
logging.error(f"mcp server info is not compatible,{self.name},version:{self.version},reason:{error_msg}")
raise NacosException(
f"mcp server info is not compatible,{self.name},version:{self.version},reason:{error_msg}"
)
if self._nacos_settings.SERVICE_REGISTER:
version = metadata.version('nacos-mcp-wrapper-python')
service_meta_data = {"source": f"nacos-mcp-wrapper-python-{version}",**self._nacos_settings.SERVICE_META_DATA}
await self.naming_client.register_instance(
request=RegisterInstanceParam(
group_name="DEFAULT_GROUP" if self._nacos_settings.SERVICE_GROUP is None else self._nacos_settings.SERVICE_GROUP,
service_name=self.get_register_service_name(),
ip=self._nacos_settings.SERVICE_IP,
port=self._nacos_settings.SERVICE_PORT if self._nacos_settings.SERVICE_PORT else port,
ephemeral=self._nacos_settings.SERVICE_EPHEMERAL,
metadata=service_meta_data,
)
)
asyncio.create_task(self.subscribe())
logging.info(f"Register to nacos success,{self.name},version:{self.version}")
except Exception as e: except Exception as e:
logging.error(f"Failed to register MCP server to Nacos: {e}") logging.error(f"Failed to register MCP server to Nacos: {e}")

View File

@ -23,9 +23,9 @@ class NacosSettings(BaseSettings):
description="nacos namespace", description="nacos namespace",
default="public") default="public")
SERVICE_GROUP : str = Field( SERVICE_GROUP : Optional[str] = Field(
description="nacos service group", description="nacos service group",
default="DEFAULT_GROUP") default=None)
SERVICE_NAME : Optional[str] = Field( SERVICE_NAME : Optional[str] = Field(
description="nacos service name", description="nacos service name",
@ -63,6 +63,10 @@ class NacosSettings(BaseSettings):
description="nacos connection labels", description="nacos connection labels",
default={}) default={})
SERVICE_META_DATA : Optional[dict] = Field(
description="nacos service metadata",
default={})
class Config: class Config:
env_prefix = "NACOS_MCP_SERVER_" env_prefix = "NACOS_MCP_SERVER_"

View File

@ -1,9 +1,9 @@
psutil==7.0.0 psutil==7.0.0
anyio==4.9.0 anyio==4.9.0
mcp==1.9.2 mcp==1.9.2
nacos-sdk-python==2.0.7 nacos-sdk-python>=2.0.9
pydantic==2.11.3 pydantic==2.11.3
pydantic-settings==2.9.1 pydantic-settings==2.9.1
jsonref==1.1.0 jsonref==1.1.0
uvicorn==0.34.2 uvicorn==0.34.2
nacos-maintainer-sdk-python==0.1.0 nacos-maintainer-sdk-python>=0.1.2

View File

@ -9,7 +9,7 @@ def read_requirements():
setup( setup(
name='nacos-mcp-wrapper-python', name='nacos-mcp-wrapper-python',
version='1.0.4', # 项目的版本号 version='1.0.9', # 项目的版本号
packages=find_packages( packages=find_packages(
exclude=["test", "*.tests", "*.tests.*", "tests.*", "tests"]), # 自动发现所有包 exclude=["test", "*.tests", "*.tests.*", "tests.*", "tests"]), # 自动发现所有包
url="https://github.com/nacos-group/nacos-mcp-wrapper-python", url="https://github.com/nacos-group/nacos-mcp-wrapper-python",