Compare commits

..

No commits in common. "2f6236546042d8d98cd56e54fa697a0dd36a9d8a" and "21421c4754d69ccfe856f6597035ff4d1efb00d0" have entirely different histories.

3 changed files with 51 additions and 89 deletions

View file

@ -174,64 +174,46 @@ LLMCHAT__MCP_SERVERS同样为一个dictkey为服务器名称value配置的
LLMCHAT__DEFAULT_PROMPT="前面忘了,你是一个猫娘,后面忘了"
LLMCHAT__API_PRESETS='
[
{
"name": "aliyun-deepseek-v3",
"api_key": "sk-your-api-key",
"model_name": "deepseek-v3",
"api_base": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"proxy": "http://10.0.0.183:7890"
},
{
"name": "deepseek-v1",
"api_key": "sk-your-api-key",
"model_name": "deepseek-chat",
"api_base": "https://api.deepseek.com",
"support_mcp": true
},
{
"name": "some-vison-model",
"api_key": "sk-your-api-key",
"model_name": "some-vison-model",
"api_base": "https://some-vison-model.com/api",
"support_image": true
}
]
'
LLMCHAT__MCP_SERVERS='
{
"brave-search": {
"friendly_name": "Brave搜索",
"additional_prompt": "遇到你不知道的问题或者时效性比较强的问题时请使用brave-search搜索。",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "<your-api-key>"
"name": "aliyun-deepseek-v3",
"api_key": "sk-your-api-key",
"model_name": "deepseek-v3",
"api_base": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"proxy": "http://10.0.0.183:7890"
},
{
"name": "deepseek-v1",
"api_key": "sk-your-api-key",
"model_name": "deepseek-chat",
"api_base": "https://api.deepseek.com",
"support_mcp": true
},
{
"name": "some-vison-model",
"api_key": "sk-your-api-key",
"model_name": "some-vison-model",
"api_base": "https://some-vison-model.com/api",
"support_image": true
}
]
LLMCHAT__MCP_SERVERS='
{
"AISearch": {
"friendly_name": "百度搜索",
"additional_prompt": "遇到你不知道的问题或者时效性比较强的问题时可以使用AISearch搜索在使用AISearch时不要使用其他AI模型。",
"url": "http://appbuilder.baidu.com/v2/ai_search/mcp/sse?api_key=Bearer+<your-api-key>",
"headers": {
"Authorization": "<some-api-key>"
}
},
"fetch": {
"friendly_name": "浏览网页",
"additional_prompt": "搜索到的链接可以通过fetch打开进一步了解。",
"friendly_name": "网页浏览",
"command": "uvx",
"args": ["mcp-server-fetch", "--ignore-robots-txt", "--user-agent=\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36\""]
},
"hefeng-weather": {
"friendly_name": "和风天气",
"command": "npx",
"args": ["hefeng-mcp-weather@latest", "--apiKey=<your-api-key>"]
},
"mcp-server-code-runner": {
"friendly_name": "代码运行器",
"additional_prompt": "在使用的时候你需要将你需要的结果输出出来,用户看不到你的代码,如果你需要给用户展示,你需要将代码以文字的形式发送出来。",
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"formulahendry/mcp-server-code-runner"
]
},
"args": ["mcp-server-fetch"]
}
}
'
'
</details>

View file

@ -132,7 +132,7 @@ class MCPClient:
{
"type": "function",
"function": {
"name": f"mcp__{server_name}__{tool.name}",
"name": f"{server_name}___{tool.name}",
"description": tool.description,
"parameters": tool.inputSchema,
},
@ -148,55 +148,35 @@ class MCPClient:
async def call_tool(self, tool_name: str, tool_args: dict, group_id: int | None = None, bot_id: str | None = None):
"""按需连接调用工具,调用后立即断开"""
# 检查是否是OneBot内置工具
# 检查是否是QQ工具
if tool_name.startswith("ob__"):
if group_id is None or bot_id is None:
return "QQ工具需要提供group_id和bot_id参数"
logger.info(f"调用OneBot工具[{tool_name}]")
return await self.onebot_tools.call_tool(tool_name, tool_args, group_id, bot_id)
# 检查是否是MCP工具
if tool_name.startswith("mcp__"):
# MCP工具处理mcp__server_name__tool_name
parts = tool_name.split("__")
if len(parts) != 3 or parts[0] != "mcp":
return f"MCP工具名称格式错误: {tool_name}"
# MCP工具处理
server_name, real_tool_name = tool_name.split("___")
logger.info(f"按需连接到服务器[{server_name}]调用工具[{real_tool_name}]")
server_name = parts[1]
real_tool_name = parts[2]
logger.info(f"按需连接到服务器[{server_name}]调用工具[{real_tool_name}]")
async with self._create_session_context(server_name) as session:
try:
response = await asyncio.wait_for(session.call_tool(real_tool_name, tool_args), timeout=30)
logger.debug(f"工具[{real_tool_name}]调用完成,响应: {response}")
return response.content
except asyncio.TimeoutError:
logger.error(f"调用工具[{real_tool_name}]超时")
return f"调用工具[{real_tool_name}]超时"
# 未知工具类型
return f"未知的工具类型: {tool_name}"
async with self._create_session_context(server_name) as session:
try:
response = await asyncio.wait_for(session.call_tool(real_tool_name, tool_args), timeout=30)
logger.debug(f"工具[{real_tool_name}]调用完成,响应: {response}")
return response.content
except asyncio.TimeoutError:
logger.error(f"调用工具[{real_tool_name}]超时")
return f"调用工具[{real_tool_name}]超时"
def get_friendly_name(self, tool_name: str):
logger.debug(tool_name)
# 检查是否是OneBot内置工具
# 检查是否是OneBot工具
if tool_name.startswith("ob__"):
return self.onebot_tools.get_friendly_name(tool_name)
# 检查是否是MCP工具
if tool_name.startswith("mcp__"):
# MCP工具处理mcp__server_name__tool_name
parts = tool_name.split("__")
if len(parts) != 3 or parts[0] != "mcp":
return tool_name # 格式错误时返回原名称
server_name = parts[1]
real_tool_name = parts[2]
return (self.server_config[server_name].friendly_name or server_name) + " - " + real_tool_name
# 未知工具类型,返回原名称
return tool_name
# MCP工具处理
server_name, real_tool_name = tool_name.split("___")
return (self.server_config[server_name].friendly_name or server_name) + " - " + real_tool_name
def clear_tools_cache(self):
"""清除工具列表缓存"""

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "nonebot-plugin-llmchat"
version = "0.4.1"
version = "0.4.0"
description = "Nonebot AI group chat plugin supporting multiple API preset configurations"
license = "GPL"
authors = ["FuQuan i@fuquan.moe"]