Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
|
f24f12c4ba | |
|
cf9477af7b | |
|
5ab63b71cd | |
|
291949b579 | |
|
8aa1fe43f9 | |
|
710139761a | |
|
dce1cfb011 |
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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_"
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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
|
2
setup.py
2
setup.py
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue