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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions astrbot/core/provider/func_tool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1057,11 +1057,14 @@ async def sync_modelscope_mcp_servers(self, access_token: str) -> None:
"mcp_server_list",
[],
)
local_mcp_config = self.load_mcp_config()
local_mcp_config = copy.deepcopy(self.load_mcp_config())

synced_count = 0
mcp_servers = local_mcp_config.setdefault("mcpServers", {})
Comment thread
VectorPeak marked this conversation as resolved.
synced_servers: list[tuple[str, dict]] = []
for server in mcp_server_list:
server_name = server["name"]
server_name = server.get("name")
if not server_name:
continue
operational_urls = server.get("operational_urls", [])
if not operational_urls:
continue
Expand All @@ -1070,28 +1073,28 @@ async def sync_modelscope_mcp_servers(self, access_token: str) -> None:
if not server_url:
continue
# 添加到配置中(同名会覆盖)
local_mcp_config["mcpServers"][server_name] = {
server_config = {
"url": server_url,
"transport": "sse",
"active": True,
"provider": "modelscope",
}
synced_count += 1
mcp_servers[server_name] = server_config
synced_servers.append((server_name, server_config))

if synced_count > 0:
if synced_servers:
self.save_mcp_config(local_mcp_config)
tasks = []
for server in mcp_server_list:
name = server["name"]
for name, config in synced_servers:
tasks.append(
self.enable_mcp_server(
name=name,
config=local_mcp_config["mcpServers"][name],
config=config,
),
)
await asyncio.gather(*tasks)
logger.info(
f"从 ModelScope 同步了 {synced_count} 个 MCP 服务器",
f"从 ModelScope 同步了 {len(synced_servers)} 个 MCP 服务器",
)
else:
logger.warning("没有找到可用的 ModelScope MCP 服务器")
Expand Down
78 changes: 78 additions & 0 deletions tests/unit/test_func_tool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest

from astrbot.core import sp
from astrbot.core.provider import func_tool_manager as ftm
from astrbot.core.provider.func_tool_manager import FunctionToolManager
from astrbot.core.tools.computer_tools.shell import ExecuteShellTool
from astrbot.core.tools.message_tools import SendMessageToUserTool
Expand Down Expand Up @@ -345,3 +346,80 @@ def test_firecrawl_tools_are_registered_as_builtin_tools():
assert extract_tool.name == "firecrawl_extract_web_page"
assert manager.is_builtin_tool("web_search_firecrawl") is True
assert manager.is_builtin_tool("firecrawl_extract_web_page") is True


@pytest.mark.asyncio
async def test_modelscope_sync_enables_only_synced_servers(monkeypatch):
class FakeResponse:
status = 200

async def __aenter__(self):
return self

async def __aexit__(self, exc_type, exc, tb):
return False

async def json(self):
return {
"data": {
"mcp_server_list": [
{
"name": "valid",
"operational_urls": [{"url": "https://example.com/mcp"}],
},
{"name": "missing-url", "operational_urls": []},
{"name": "empty-url", "operational_urls": [{}]},
{"operational_urls": [{"url": "https://example.com/no-name"}]},
]
}
}

class FakeSession:
async def __aenter__(self):
return self

async def __aexit__(self, exc_type, exc, tb):
return False

def get(self, *_args, **_kwargs):
return FakeResponse()

saved_configs = []
enabled_servers = []
default_config = {"mcpServers": {}}
manager = FunctionToolManager()

async def fake_enable_mcp_server(name, config):
enabled_servers.append((name, config))

monkeypatch.setattr(ftm.aiohttp, "ClientSession", lambda: FakeSession())
monkeypatch.setattr(manager, "load_mcp_config", lambda: default_config)
monkeypatch.setattr(manager, "save_mcp_config", saved_configs.append)
monkeypatch.setattr(manager, "enable_mcp_server", fake_enable_mcp_server)

await manager.sync_modelscope_mcp_servers("token")

assert default_config == {"mcpServers": {}}
assert saved_configs == [
{
"mcpServers": {
"valid": {
"url": "https://example.com/mcp",
"transport": "sse",
"active": True,
"provider": "modelscope",
}
}
}
]
assert enabled_servers == [
(
"valid",
{
"url": "https://example.com/mcp",
"transport": "sse",
"active": True,
"provider": "modelscope",
},
)
]
Loading