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
26 changes: 25 additions & 1 deletion astrbot/core/agent/mcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,14 +679,38 @@ async def cleanup(self) -> None:
self.running_event.set()



def clean_tool_name(server_name: str, tool_name: str, max_length: int = 64) -> str:
"""构建前缀化的 MCP 工具名,确保兼容 LLM API 的命名规范。

LLM API(OpenAI、Anthropic、Gemini 等)的工具名只允许
[a-zA-Z0-9_-] 字符,且通常限制 64 字符。

使用双下划线 __ 作为分隔符,并对非法字符做清洗而非报错,
让工具在多数场景下仍可正常工作。
"""
safe_server = re.sub(r"[^a-zA-Z0-9_\-]", "_", server_name)
safe_tool = re.sub(r"[^a-zA-Z0-9_\-]", "_", tool_name)
prefixed = f"{safe_server}__{safe_tool}"
if len(prefixed) > max_length:
# 优先截断工具名部分
excess = len(prefixed) - max_length
if len(safe_tool) > excess + 3:
safe_tool = safe_tool[:len(safe_tool) - excess - 3] + "..."
else:
safe_tool = safe_tool[:max(3, len(safe_tool) - excess)]
prefixed = f"{safe_server}__{safe_tool}"
return prefixed


class MCPTool(FunctionTool, Generic[TContext]):
"""A function tool that calls an MCP service."""

def __init__(
self, mcp_tool: mcp.Tool, mcp_client: MCPClient, mcp_server_name: str, **kwargs
) -> None:
super().__init__(
name=mcp_tool.name,
name=clean_tool_name(mcp_server_name, mcp_tool.name),
description=mcp_tool.description or "",
parameters=_normalize_mcp_input_schema(mcp_tool.inputSchema),
)
Expand Down
7 changes: 5 additions & 2 deletions astrbot/dashboard/services/tools_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Any

from astrbot.core import logger, sp
from astrbot.core.agent.mcp_client import MCPTool, validate_mcp_stdio_config
from astrbot.core.agent.mcp_client import MCPTool, clean_tool_name, validate_mcp_stdio_config
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
from astrbot.core.star import star_map
from astrbot.core.tools.registry import get_builtin_tool_config_statuses
Expand Down Expand Up @@ -79,7 +79,10 @@ def get_mcp_servers(self) -> list[dict]:
for name_key, runtime in self.tool_mgr.mcp_server_runtime_view.items():
if name_key == name:
mcp_client = runtime.client
server_info["tools"] = [tool.name for tool in mcp_client.tools]
server_info["tools"] = [
clean_tool_name(name, tool.name)
for tool in mcp_client.tools
]
server_info["errlogs"] = mcp_client.server_errlogs
break
else:
Expand Down