Compare commits

...

7 Commits
1.0.1 ... 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
Sunrisea 8aa1fe43f9
update nacos-sdk-python to version 2.0.7 (#15) 2025-07-11 16:08:26 +08:00
Sunrisea 710139761a
Update mcp version logic and fix bug (#14)
* Optimize version logic and fix bug

* update version to 1.0.3

* update readme
2025-07-02 19:10:56 +08:00
Sunrisea dce1cfb011
Fix bug and release version 1.0.2 (#13) 2025-07-01 20:44:53 +08:00
10 changed files with 124 additions and 47 deletions

View File

@ -44,7 +44,10 @@ from nacos_mcp_wrapper.server.nacos_settings import NacosSettings
# mcp = FastMCP("Demo")
nacos_settings = NacosSettings()
nacos_settings.SERVER_ADDR = "<nacos_server_addr> e.g.127.0.0.1:8848"
mcp = NacosMCP("nacos-mcp-python",nacos_settings=nacos_settings)
mcp = NacosMCP("nacos-mcp-python", nacos_settings=nacos_settings,
port=18001,
instructions="This is a simple Nacos MCP server",
version="1.0.0")
# Add an addition tool

View File

@ -45,7 +45,10 @@ from nacos_mcp_wrapper.server.nacos_settings import NacosSettings
# mcp = FastMCP("Demo")
nacos_settings = NacosSettings()
nacos_settings.SERVER_ADDR = "<nacos_server_addr> e.g.127.0.0.1:8848"
mcp = NacosMCP("nacos-mcp-python",nacos_settings=nacos_settings)
mcp = NacosMCP("nacos-mcp-python", nacos_settings=nacos_settings,
port=18001,
instructions="This is a simple Nacos MCP server",
version="1.0.0")
# Add an addition tool

View File

@ -6,7 +6,10 @@ nacos_settings = NacosSettings()
nacos_settings.SERVER_ADDR = "127.0.0.1:8848" # <nacos_server_addr> e.g. 127.0.0.1:8848
nacos_settings.USERNAME=""
nacos_settings.PASSWORD=""
mcp = NacosMCP("nacos-mcp-python", nacos_settings=nacos_settings, port=18001)
mcp = NacosMCP("nacos-mcp-python", nacos_settings=nacos_settings,
port=18001,
instructions="This is a simple Nacos MCP server",
version="1.0.0")
# Register an addition tool
@mcp.tool()

View File

@ -24,7 +24,6 @@ async def main(
port: int=7001,
) -> int:
# Configure logging
print("hahaha")
logging.basicConfig(
level=getattr(logging, log_level.upper()),
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",

View File

@ -28,8 +28,11 @@ class NacosMCP(FastMCP):
event_store: EventStore | None = None,
*,
tools: list[Tool] | None = None,
version: str | None = None,
**settings: Any,
):
if "host" not in settings:
settings["host"] = "0.0.0.0"
super().__init__(name, instructions, auth_server_provider, event_store,
tools=tools, **settings)
@ -37,6 +40,7 @@ class NacosMCP(FastMCP):
nacos_settings=nacos_settings,
name=name or "FastMCP",
instructions=instructions,
version=version,
lifespan=lifespan_wrapper(self, self.settings.lifespan)
if self.settings.lifespan
else default_lifespan,

View File

@ -3,6 +3,7 @@ import json
import logging
from contextlib import AbstractAsyncContextManager
from typing import Literal, Callable, Any
from importlib import metadata
import jsonref
from maintainer.ai.model.nacos_mcp_info import McpToolMeta, McpServerDetailInfo, \
@ -22,7 +23,7 @@ from v2.nacos import NacosNamingService, RegisterInstanceParam, \
from nacos_mcp_wrapper.server.nacos_settings import NacosSettings
from nacos_mcp_wrapper.server.utils import get_first_non_loopback_ip, \
jsonref_default, compare
jsonref_default, compare, pkg_version
logger = logging.getLogger(__name__)
@ -45,7 +46,7 @@ class NacosServer(Server):
] = lifespan,
):
if version is None:
version = "1.0.0"
version = pkg_version("mcp")
super().__init__(name, version, instructions, lifespan)
if nacos_settings == None:
@ -188,29 +189,30 @@ class NacosServer(Server):
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:
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:
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:
checkToolsResult = self.check_tools_compatible(server_detail_info)
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
if not self.is_service_ref_same(mcp_service_ref):
return False
is_same_service,error_msg = self.is_service_ref_same(mcp_service_ref)
if not is_same_service:
return False, error_msg
return True
return True, ""
def is_service_ref_same(self,mcp_service_ref:McpServiceRef) -> bool:
if self.get_register_service_name() != mcp_service_ref.serviceName:
return False
if mcp_service_ref.groupName != self._nacos_settings.SERVICE_GROUP:
return False
def is_service_ref_same(self,mcp_service_ref:McpServiceRef) -> (bool,str):
if self._nacos_settings.SERVICE_NAME is not None and self._nacos_settings.SERVICE_NAME != mcp_service_ref.serviceName:
return False, f"service name not compatible, local service name:{self._nacos_settings.SERVICE_NAME}, remote service name:{mcp_service_ref.serviceName}"
if self._nacos_settings.SERVICE_GROUP is not None and self._nacos_settings.SERVICE_GROUP != mcp_service_ref.groupName:
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:
return False
return True
return False, f"namespace id not compatible, local namespace id:{self._nacos_settings.NAMESPACE}, remote namespace id:{mcp_service_ref.namespaceId}"
return True, ""
def get_register_service_name(self) -> str:
@ -234,7 +236,6 @@ class NacosServer(Server):
self.name,
self.version
)
print(server_detail_info.model_dump_json())
if server_detail_info is not None:
self.update_tools(server_detail_info)
except Exception as e:
@ -250,6 +251,8 @@ class NacosServer(Server):
self.mcp_service = await NacosAIMaintainerService.create_mcp_service(
self._ai_client_config
)
self.naming_client = await NacosNamingService.create_naming_service(
self._naming_client_config)
server_detail_info = None
try:
server_detail_info = await self.mcp_service.get_mcp_server_detail(
@ -265,14 +268,32 @@ class NacosServer(Server):
self.list_tools()(self._list_tmp_tools)
if server_detail_info is not None:
if not self.check_compatible(server_detail_info):
logging.error(f"mcp server info is not compatible,{self.name},version:{self.version}")
is_compatible, error_msg = self.check_compatible(server_detail_info)
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}"
f"mcp server info is not compatible,{self.name},version:{self.version},reason:{error_msg}"
)
if types.ListToolsRequest in self.request_handlers:
self.update_tools(server_detail_info)
asyncio.create_task(self.subscribe())
if self._nacos_settings.SERVICE_REGISTER and (self.type == "mcp-sse"
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(
request=RegisterInstanceParam(
group_name=server_detail_info.remoteServerConfig.serviceRef.groupName,
service_name=server_detail_info.remoteServerConfig.serviceRef.serviceName,
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
)
)
logging.info(f"Register to nacos success,{self.name},version:{self.version}")
return
mcp_tool_specification = None
@ -304,7 +325,7 @@ class NacosServer(Server):
endpoint_spec.type = "REF"
data = {
"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,
}
endpoint_spec.data = data
@ -314,23 +335,53 @@ class NacosServer(Server):
server_basic_info.remoteServerConfig = remote_server_config_info
server_basic_info.protocol = self.type
server_basic_info.frontProtocol = self.type
if self._nacos_settings.SERVICE_REGISTER:
naming_client = await NacosNamingService.create_naming_service(
self._naming_client_config)
await 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:
await self.mcp_service.create_mcp_server(self._nacos_settings.NAMESPACE,
self.name,
server_basic_info,
mcp_tool_specification,
endpoint_spec)
except Exception as e:
logger.info(f"Found MCP server {self.name} in Nacos,try to update it")
version_detail = None
try:
version_detail = await self.mcp_service.get_mcp_server_detail(
self._nacos_settings.NAMESPACE,
self.name,
self.version
)
await self.mcp_service.create_mcp_server(self._nacos_settings.NAMESPACE,
self.name,
server_basic_info,
mcp_tool_specification,
endpoint_spec)
except Exception as e_2:
logger.info(f" Version {self.version} of Mcp server {self.name} is not in Nacos, try to update it")
if version_detail is None:
await self.mcp_service.update_mcp_server(
self._nacos_settings.NAMESPACE,
self.name,
True,
server_basic_info,
mcp_tool_specification,
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:
logging.error(f"Failed to register MCP server to Nacos: {e}")

View File

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

View File

@ -15,6 +15,16 @@ def get_first_non_loopback_ip():
return addr.address
return None
def pkg_version(package: str) -> str:
try:
from importlib.metadata import version
return version(package)
except Exception:
pass
return "1.0.0"
def jsonref_default(obj):
if isinstance(obj, jsonref.JsonRef):
return obj.__subject__

View File

@ -1,9 +1,9 @@
psutil==7.0.0
anyio==4.9.0
mcp==1.9.2
nacos-sdk-python==2.0.4
nacos-sdk-python>=2.0.9
pydantic==2.11.3
pydantic-settings==2.9.1
jsonref==1.1.0
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(
name='nacos-mcp-wrapper-python',
version='1.0.1', # 项目的版本号
version='1.0.9', # 项目的版本号
packages=find_packages(
exclude=["test", "*.tests", "*.tests.*", "tests.*", "tests"]), # 自动发现所有包
url="https://github.com/nacos-group/nacos-mcp-wrapper-python",