From 1072f0065076b67a0528d8e9f51bb3869c06b265 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 13:13:56 +0800 Subject: [PATCH 01/16] docs(utils): clarify message parsing description for history records Update docstring to accurately reflect that reply messages are supported in history parsing rather than forward messages. Add comment explaining that forward messages only store a simple marker since AI can use get_forward_msg tool to view full content. --- src/Undefined/utils/common.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Undefined/utils/common.py b/src/Undefined/utils/common.py index 94381a91..f8136aa1 100644 --- a/src/Undefined/utils/common.py +++ b/src/Undefined/utils/common.py @@ -54,7 +54,7 @@ async def parse_message_content_for_history( bot_qq: int, get_msg_func: Callable[[int], Awaitable[dict[str, Any] | None]] | None = None, ) -> str: - """解析消息内容用于历史记录(支持合并转发和 @ 格式化) + """解析消息内容用于历史记录(支持回复引用和 @ 格式化) 参数: message_content: 消息内容列表 @@ -101,6 +101,7 @@ async def parse_message_content_for_history( elif type_ == "forward": msg_id = data.get("id") if msg_id: + # 合并转发只保存简单标记,AI 可以通过 get_forward_msg 工具查看完整内容 texts.append(f"[合并转发: {msg_id}]") elif type_ == "reply": From 4dcc2177f0e559685af8230f4c0572c3570f2b87 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:23:55 +0800 Subject: [PATCH 02/16] feat(mcp): add Model Context Protocol support layer Add comprehensive MCP (Model Context Protocol) compatibility layer to enable connecting external MCP servers and extending AI capabilities. Core Implementation: - Add MCPToolSetRegistry class to manage MCP server connections and tool registration - Integrate MCP toolsets into ToolRegistry with async initialization and graceful degradation - Implement lazy loading via background tasks to avoid blocking startup - Support tool naming convention: mcp.{server_name}.{tool_name} Configuration: - Add MCP_CONFIG_PATH environment variable to .env.example - Create config/mcp.json.example with sample server configurations (filesystem, brave-search, sqlite, github, postgres) - Update .gitignore to exclude config/mcp.json Dependencies: - Add fastmcp>=2.14.4 dependency for MCP client functionality Integration: - Update AIClient to initialize MCP toolsets asynchronously on startup - Add proper cleanup in AIClient.close() to terminate MCP connections - Update ToolRegistry to load, initialize, and close MCP toolsets Documentation: - Add MCP support section to README.md with configuration guide - Create comprehensive MCP toolset documentation with usage examples and troubleshooting guide Features: - Automatic tool discovery and registration from MCP servers - Graceful error handling when MCP servers are unavailable - Detailed logging for debugging and monitoring - Support for multiple concurrent MCP servers --- .env.example | 5 + .gitignore | 9 +- README.md | 33 + config/mcp.json.example | 8 + pyproject.toml | 1 + src/Undefined/ai.py | 21 +- src/Undefined/skills/tools/__init__.py | 66 +- src/Undefined/skills/toolsets/mcp/README.md | 151 ++++ src/Undefined/skills/toolsets/mcp/__init__.py | 255 ++++++ uv.lock | 803 +++++++++++++++++- 10 files changed, 1339 insertions(+), 13 deletions(-) create mode 100644 config/mcp.json.example create mode 100644 src/Undefined/skills/toolsets/mcp/README.md create mode 100644 src/Undefined/skills/toolsets/mcp/__init__.py diff --git a/.env.example b/.env.example index c047b8e4..5ec9c455 100644 --- a/.env.example +++ b/.env.example @@ -73,3 +73,8 @@ WEATHER_API_KEY= # 心知天气API密钥,从 https://www.sen # XXAPI API 配置 # ================================ XXAPI_API_TOKEN= # XXAPI Token,前往 https://xxapi.cn 获取 + +# ================================ +# MCP (Model Context Protocol) 配置 +# ================================ +MCP_CONFIG_PATH=config/mcp.json # MCP 配置文件路径(相对于工作目录) diff --git a/.gitignore b/.gitignore index 46911b50..2de9f3ce 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,11 @@ AGENTS.md .DS_Store .claude/ -config.local.json \ No newline at end of file +config.local.json + +.vscode +.ruff_cache +dist/ + +# MCP 配置 +config/mcp.json \ No newline at end of file diff --git a/README.md b/README.md index fc6a5166..e8522261 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ - **并行工具执行**:无论是主 AI 还是子 Agent,均支持 `asyncio` 并发工具调用,大幅提升多任务处理速度(如同时读取多个文件或搜索多个关键词)。 - **智能 Agent 矩阵**:内置多个专业 Agent,分工协作处理复杂任务。 - **定时任务系统**:支持 Crontab 语法的强大定时任务系统,可自动执行各种操作(如定时提醒、定时搜索)。 +- **MCP 协议支持**:支持通过 MCP (Model Context Protocol) 连接外部工具和数据源,扩展 AI 能力。 - **思维链支持**:支持开启思维链,提升复杂逻辑推理能力。 - **高并发架构**:基于 `asyncio` 全异步设计,支持多队列消息处理与工具并发执行,轻松应对高并发场景。 - **安全防护**:内置独立的安全模型,实时检测注入攻击与恶意内容。 @@ -209,6 +210,38 @@ Undefined 采用模块化的 **Skills** 架构,扩展非常简单: 详细开发指南请参考 [src/Undefined/skills/README.md](src/Undefined/skills/README.md)。 +### MCP 支持 + +Undefined 支持 MCP (Model Context Protocol) 协议,可以连接外部 MCP 服务器来扩展 AI 的工具能力。 + +#### 配置 MCP + +1. 复制 MCP 配置示例文件: + ```bash + cp config/mcp.json.example config/mcp.json + ``` + +2. 编辑 `config/mcp.json` ,根据 MCP 服务器说明使用标准格式添加你需要的 MCP 服务器 + +3. 在 `.env` 中设置 MCP 配置文件路径(可选,默认为 `config/mcp.json`): + ```env + MCP_CONFIG_PATH=config/mcp.json + ``` + +#### 使用 MCP 工具 + +配置完成后,AI 会自动加载 MCP 工具,工具名称格式为 `mcp.{server_name}.{tool_name}`。 + +例如,配置了 `filesystem` 服务器后,AI 可以使用 `mcp.filesystem.read_file` 等工具。 + +#### 默认可用的 MCP 服务器 + +> 需确保本地安装了`nodejs`以及`npm` + +- [@upstash/context7-mcp](https://github.com/upstash/context7):Up-to-date Code Docs For Any Prompt + +> 更多服务器请自行添加 + ## 致谢与友链 ### NagaAgent diff --git a/config/mcp.json.example b/config/mcp.json.example new file mode 100644 index 00000000..553d5d48 --- /dev/null +++ b/config/mcp.json.example @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "context7": { + "command": "npx", + "args": ["-y", "@upstash/context7-mcp"] + } + } +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 4c2f6148..a238e485 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ dependencies = [ "openpyxl>=3.1.5", "py7zr>=1.1.0", "rarfile>=4.2", + "fastmcp>=2.14.4", ] [project.urls] diff --git a/src/Undefined/ai.py b/src/Undefined/ai.py index 16220d59..2525277e 100644 --- a/src/Undefined/ai.py +++ b/src/Undefined/ai.py @@ -140,12 +140,31 @@ def __init__( ) self._tokenizer = None + # 异步初始化 MCP 工具集(在后台任务中完成) + async def init_mcp_async() -> None: + try: + await self.tool_registry.initialize_mcp_toolsets() + except Exception as e: + logger.warning(f"异步初始化 MCP 工具集失败: {e}") + + # 创建后台任务初始化 MCP + self._mcp_init_task = asyncio.create_task(init_mcp_async()) + logger.info("[初始化] AIClient 初始化完成") async def close(self) -> None: - """关闭 HTTP 客户端""" + """关闭 HTTP 客户端和 MCP 连接""" logger.info("[清理] 正在关闭 AIClient HTTP 客户端...") await self._http_client.aclose() + + # 关闭 MCP 工具集连接 + if hasattr(self, "tool_registry"): + await self.tool_registry.close_mcp_toolsets() + + # 等待 MCP 初始化任务完成(如果还在运行) + if hasattr(self, "_mcp_init_task") and not self._mcp_init_task.done(): + await self._mcp_init_task + logger.info("[清理] AIClient 已关闭") def count_tokens(self, text: str) -> int: diff --git a/src/Undefined/skills/tools/__init__.py b/src/Undefined/skills/tools/__init__.py index 1776d801..489c33f8 100644 --- a/src/Undefined/skills/tools/__init__.py +++ b/src/Undefined/skills/tools/__init__.py @@ -1,9 +1,12 @@ import logging from pathlib import Path -from typing import Dict, Any, List +from typing import Dict, Any, List, TYPE_CHECKING from ..registry import BaseRegistry +if TYPE_CHECKING: + from ..toolsets.mcp import MCPToolSetRegistry + logger = logging.getLogger(__name__) @@ -17,11 +20,14 @@ def __init__(self, tools_dir: str | Path | None = None): super().__init__(tools_path) + # 初始化 MCP 工具集注册表 + self._mcp_registry: MCPToolSetRegistry | None = None + # 自动加载 self.load_tools() def load_tools(self) -> None: - """从 tools 目录发现并加载工具,同时也加载 toolsets。""" + """从 tools 目录发现并加载工具,同时也加载 toolsets 和 MCP 工具集。""" # 1. 加载 tools 目录下的非分类工具 self.load_items() @@ -30,10 +36,16 @@ def load_tools(self) -> None: self.toolsets_dir = self.base_dir.parent / "toolsets" self._load_toolsets_recursive() - # 3. 输出详细的工具列表 + # 3. 加载 MCP 工具集(创建注册表,但不初始化) + self._load_mcp_toolsets() + + # 4. 输出详细的工具列表 tool_names = list(self._items_handlers.keys()) basic_tools = [name for name in tool_names if "." not in name] - toolset_tools = [name for name in tool_names if "." in name] + toolset_tools = [ + name for name in tool_names if "." in name and not name.startswith("mcp.") + ] + mcp_tools = [name for name in tool_names if name.startswith("mcp.")] # 按 toolsets 分类整理 toolset_by_category: Dict[str, List[str]] = {} @@ -52,6 +64,8 @@ def load_tools(self) -> None: logger.info(f" - 工具集工具 ({len(toolset_tools)} 个):") for category, tools in sorted(toolset_by_category.items()): logger.info(f" [{category}] ({len(tools)} 个): {', '.join(tools)}") + if mcp_tools: + logger.info(f" - MCP 工具 ({len(mcp_tools)} 个): {', '.join(mcp_tools)}") logger.info(f" - 总计: {len(tool_names)} 个工具") logger.info("=" * 60) @@ -80,6 +94,50 @@ def _load_toolsets_recursive(self) -> None: # 使用基类方法加载,指定前缀 self._load_item_from_dir(tool_dir, prefix=f"{category_name}.") + def _load_mcp_toolsets(self) -> None: + """加载 MCP 工具集(创建注册表,但不初始化)""" + try: + from ..toolsets.mcp import MCPToolSetRegistry + + # 创建 MCP 工具集注册表 + self._mcp_registry = MCPToolSetRegistry() + logger.info("MCP 工具集注册表已创建(待初始化)") + + except ImportError as e: + logger.warning(f"无法导入 MCP 工具集注册表: {e}") + self._mcp_registry = None + + async def initialize_mcp_toolsets(self) -> None: + """异步初始化 MCP 工具集 + + 需要在 AIClient 初始化后调用。 + """ + if hasattr(self, "_mcp_registry") and self._mcp_registry: + try: + await self._mcp_registry.initialize() + + # 将 MCP 工具添加到主注册表 + for schema in self._mcp_registry.get_tools_schema(): + self._items_schema.append(schema) + + for tool_name, handler in self._mcp_registry._tools_handlers.items(): + self._items_handlers[tool_name] = handler + + logger.info( + f"MCP 工具集已集成到主注册表,共 {len(self._mcp_registry._tools_handlers)} 个工具" + ) + + except Exception as e: + logger.exception(f"初始化 MCP 工具集失败: {e}") + + async def close_mcp_toolsets(self) -> None: + """关闭 MCP 工具集连接""" + if hasattr(self, "_mcp_registry") and self._mcp_registry: + try: + await self._mcp_registry.close() + except Exception as e: + logger.warning(f"关闭 MCP 工具集时出错: {e}") + # --- 兼容性别名 --- def get_tools_schema(self) -> List[Dict[str, Any]]: diff --git a/src/Undefined/skills/toolsets/mcp/README.md b/src/Undefined/skills/toolsets/mcp/README.md new file mode 100644 index 00000000..24bffdec --- /dev/null +++ b/src/Undefined/skills/toolsets/mcp/README.md @@ -0,0 +1,151 @@ +# MCP (Model Context Protocol) 工具集 + +MCP 工具集允许 Undefined 机器人连接外部 MCP 服务器,扩展 AI 的工具能力。 + +## 架构 + +MCP 工具集通过 `MCPToolSetRegistry` 实现,负责: + +1. 加载 MCP 配置文件(`config/mcp.json`) +2. 连接配置的 MCP 服务器 +3. 获取服务器提供的工具列表 +4. 将 MCP 工具转换为 toolsets 格式 +5. 集成到主工具注册表中 + +## 工具命名 + +MCP 工具的命名格式为:`mcp.{server_name}.{tool_name}` + +例如: +- `mcp.filesystem.read_file` +- `mcp.brave-search.search` +- `mcp.sqlite.query` + +## 配置 + +### MCP 配置文件格式 + +```json +{ + "mcpServers": [ + { + "name": "server_name", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-name", "arg1", "arg2"] + } + ] +} +``` + +### 环境变量 + +- `MCP_CONFIG_PATH`:MCP 配置文件路径(默认:`config/mcp.json`) + +## 使用示例 + +### 1. 文件系统访问 + +```json +{ + "mcpServers": [ + { + "name": "filesystem", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/data"] + } + ] +} +``` + +AI 可以使用: +- `mcp.filesystem.read_file`:读取文件 +- `mcp.filesystem.write_file`:写入文件 +- `mcp.filesystem.list_directory`:列出目录 + +### 2. Web 搜索 + +```json +{ + "mcpServers": [ + { + "name": "brave-search", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-brave-search"] + } + ] +} +``` + +AI 可以使用: +- `mcp.brave-search.search`:执行搜索 + +### 3. 数据库查询 + +```json +{ + "mcpServers": [ + { + "name": "sqlite", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-sqlite", "--db-path", "/path/to/db.sqlite"] + } + ] +} +``` + +AI 可以使用: +- `mcp.sqlite.query`:执行 SQL 查询 + +### 4. GitHub API + +```json +{ + "mcpServers": [ + { + "name": "github", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-github"] + } + ] +} +``` + +AI 可以使用: +- `mcp.github.get_repository`:获取仓库信息 +- `mcp.github.list_issues`:列出 Issues + +## 注意事项 + +1. **依赖安装**:使用 MCP 功能需要安装 `fastmcp` 库 +2. **Node.js 要求**:某些 MCP 服务器需要 Node.js 环境 +3. **安全性**:配置文件包含敏感信息,已添加到 `.gitignore` +4. **性能**:MCP 工具调用需要网络或进程间通信,可能较慢 +5. **错误处理**:MCP 服务器不可用时会优雅降级,不影响其他功能 + +## 故障排除 + +### MCP 工具未加载 + +1. 检查 `fastmcp` 是否安装:`pip list | grep fastmcp` +2. 检查配置文件路径是否正确 +3. 查看日志中的错误信息 + +### MCP 工具调用失败 + +1. 检查 MCP 服务器是否正常运行 +2. 检查工具参数是否正确 +3. 查看日志中的详细错误信息 + +### Node.js 相关问题 + +如果使用基于 Node.js 的 MCP 服务器: + +1. 确保已安装 Node.js:`node --version` +2. 确保 `npx` 可用:`npx --version` +3. 检查网络连接(首次运行需要下载包) + +## 更多资源 + +- [MCP 官方文档](https://modelcontextprotocol.io/) +- [MCP Servers 仓库](https://github.com/modelcontextprotocol/servers) +- [fastmcp 文档](https://github.com/jlowin/fastmcp) \ No newline at end of file diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py new file mode 100644 index 00000000..ede7294a --- /dev/null +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -0,0 +1,255 @@ +"""MCP (Model Context Protocol) 工具集注册表 + +将 MCP 服务器转换为 toolsets,使 AI 可以调用 MCP 提供的工具。 +""" + +import json +import logging +import asyncio +from pathlib import Path +from typing import Dict, Any, List, Callable, Awaitable, cast + +logger = logging.getLogger(__name__) + + +class MCPToolSetRegistry: + """MCP 工具集注册表 + + 负责加载 MCP 配置,连接 MCP 服务器,并将 MCP 工具转换为 toolsets 格式。 + """ + + def __init__(self, config_path: str | Path | None = None) -> None: + """ + 初始化 MCP 工具集注册表。 + + 参数: + config_path: MCP 配置文件路径。如果为 None,则尝试从环境变量读取。 + """ + if config_path is None: + import os + + config_path = os.getenv("MCP_CONFIG_PATH", "config/mcp.json") + + self.config_path: Path = Path(config_path) + self._tools_schema: List[Dict[str, Any]] = [] + self._tools_handlers: Dict[ + str, Callable[[Dict[str, Any], Dict[str, Any]], Awaitable[str]] + ] = {} + self._mcp_clients: Dict[str, Any] = {} # server_name -> client + self._server_tools: Dict[str, List[str]] = {} # server_name -> tool_names + self._is_initialized: bool = False + + def load_mcp_config(self) -> Dict[str, Any]: + """加载 MCP 配置文件 + + 返回: + MCP 配置字典 + """ + if not self.config_path.exists(): + logger.warning(f"MCP 配置文件不存在: {self.config_path}") + return {"mcpServers": []} + + try: + with open(self.config_path, "r", encoding="utf-8") as f: + config = json.load(f) + logger.info(f"已加载 MCP 配置: {self.config_path}") + return cast(Dict[str, Any], config) + except json.JSONDecodeError as e: + logger.error(f"MCP 配置文件格式错误: {e}") + return {"mcpServers": []} + except Exception as e: + logger.error(f"加载 MCP 配置失败: {e}") + return {"mcpServers": []} + + async def initialize(self) -> None: + """初始化 MCP 工具集 + + 加载配置,连接 MCP 服务器,获取工具列表并转换为 toolsets 格式。 + """ + self._tools_schema = [] + self._tools_handlers = {} + self._mcp_clients = {} + self._server_tools = {} + + config = self.load_mcp_config() + servers = config.get("mcpServers", []) + + if not servers: + logger.info("未配置 MCP 服务器") + self._is_initialized = True + return + + logger.info(f"开始初始化 {len(servers)} 个 MCP 服务器...") + + for server_config in servers: + await self._initialize_server(server_config) + + total_tools = len(self._tools_handlers) + logger.info(f"MCP 工具集初始化完成,共加载 {total_tools} 个工具") + + # 输出详细统计 + for server_name, tools in self._server_tools.items(): + logger.info(f" - [{server_name}] ({len(tools)} 个): {', '.join(tools)}") + + self._is_initialized = True + + async def _initialize_server(self, server_config: Dict[str, Any]) -> None: + """初始化单个 MCP 服务器 + + 参数: + server_config: 服务器配置,包含 name、command、args 等字段 + """ + server_name = server_config.get("name") + if not server_name: + logger.error("MCP 服务器配置缺少 name 字段") + return + + try: + # 延迟导入 fastmcp + from fastmcp import Client + + # 创建客户端 + client = Client(server_config) + + # 连接并初始化 + async with client: + if not client.is_connected(): + logger.warning(f"无法连接到 MCP 服务器: {server_name}") + return + + # 获取工具列表 + tools = await client.list_tools() + + # 保存客户端引用(用于后续调用) + self._mcp_clients[server_name] = client + self._server_tools[server_name] = [] + + # 转换每个工具为 toolsets 格式 + for tool in tools: + await self._register_tool(server_name, tool, client) + + logger.info( + f"MCP 服务器 [{server_name}] 初始化成功,加载 {len(tools)} 个工具" + ) + + except ImportError: + logger.error("fastmcp 库未安装,MCP 功能将不可用") + except Exception as e: + logger.exception(f"初始化 MCP 服务器 [{server_name}] 失败: {e}") + + async def _register_tool( + self, + server_name: str, + tool: Any, + client: Any, + ) -> None: + """注册单个 MCP 工具 + + 参数: + server_name: 服务器名称 + tool: MCP 工具对象 + client: MCP 客户端实例 + """ + try: + # 获取工具信息 + tool_name = tool.name + tool_description = tool.description or "" + + # 构建工具参数 schema + parameters = tool.inputSchema if hasattr(tool, "inputSchema") else {} + + # 构建完整的工具名称:mcp.{server_name}.{tool_name} + full_tool_name = f"mcp.{server_name}.{tool_name}" + + # 构建 OpenAI function calling 格式的 schema + schema = { + "type": "function", + "function": { + "name": full_tool_name, + "description": f"[MCP:{server_name}] {tool_description}", + "parameters": parameters, + }, + } + + # 创建异步处理器 + async def handler(args: Dict[str, Any], context: Dict[str, Any]) -> str: + """MCP 工具处理器""" + try: + # 调用 MCP 工具 + result = await client.call_tool(tool_name, args) + + # 解析结果 + if hasattr(result, "content") and result.content: + # 提取文本内容 + text_parts = [] + for item in result.content: + if hasattr(item, "text"): + text_parts.append(item.text) + return "\n".join(text_parts) if text_parts else str(result) + else: + return str(result) + + except Exception as e: + logger.exception(f"调用 MCP 工具 {full_tool_name} 失败: {e}") + return f"调用 MCP 工具失败: {str(e)}" + + # 注册工具 + self._tools_schema.append(schema) + self._tools_handlers[full_tool_name] = handler + self._server_tools[server_name].append(tool_name) + + logger.debug(f"已注册 MCP 工具: {full_tool_name}") + + except Exception as e: + logger.error(f"注册 MCP 工具失败 [{server_name}/{tool.name}]: {e}") + + def get_tools_schema(self) -> List[Dict[str, Any]]: + """获取所有 MCP 工具的 Schema""" + return self._tools_schema + + async def execute_tool( + self, + tool_name: str, + args: Dict[str, Any], + context: Dict[str, Any], + ) -> str: + """执行指定的 MCP 工具 + + 参数: + tool_name: 工具名称(格式:mcp.{server_name}.{tool_name}) + args: 工具参数 + context: 执行上下文 + + 返回: + 工具执行结果 + """ + handler = self._tools_handlers.get(tool_name) + if not handler: + return f"未找到 MCP 工具: {tool_name}" + + try: + start_time = asyncio.get_event_loop().time() + result = await handler(args, context) + duration = asyncio.get_event_loop().time() - start_time + logger.info(f"[MCP工具执行] {tool_name} 耗时={duration:.4f}s") + return str(result) + except Exception as e: + logger.exception(f"[MCP工具异常] 执行工具 {tool_name} 时出错") + return f"执行 MCP 工具 {tool_name} 时出错: {str(e)}" + + async def close(self) -> None: + """关闭所有 MCP 客户端连接""" + logger.info("正在关闭 MCP 客户端连接...") + for server_name, client in self._mcp_clients.items(): + try: + # fastmcp.Client 使用 context manager,连接会自动关闭 + logger.debug(f"已关闭 MCP 服务器 [{server_name}] 连接") + except Exception as e: + logger.warning(f"关闭 MCP 服务器 [{server_name}] 连接时出错: {e}") + self._mcp_clients.clear() + logger.info("MCP 客户端连接已全部关闭") + + @property + def is_initialized(self) -> bool: + """检查是否已初始化""" + return self._is_initialized diff --git a/uv.lock b/uv.lock index edf5b77e..654f7193 100644 --- a/uv.lock +++ b/uv.lock @@ -243,6 +243,18 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] +[[package]] +name = "authlib" +version = "1.6.6" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bb/9b/b1661026ff24bc641b76b78c5222d614776b0c085bcfdac9bd15a1cb4b35/authlib-1.6.6.tar.gz", hash = "sha256:45770e8e056d0f283451d9996fbb59b70d45722b45d854d58f32878d0a40c38e", size = 164894, upload-time = "2025-12-12T08:01:41.464Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/54/51/321e821856452f7386c4e9df866f196720b1ad0c5ea1623ea7399969ae3b/authlib-1.6.6-py2.py3-none-any.whl", hash = "sha256:7d9e9bc535c13974313a87f53e8430eb6ea3d1cf6ae4f6efcd793f2e949143fd", size = 244005, upload-time = "2025-12-12T08:01:40.209Z" }, +] + [[package]] name = "backports-asyncio-runner" version = "1.2.0" @@ -252,6 +264,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, ] +[[package]] +name = "backports-tarfile" +version = "1.2.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", size = 86406, upload-time = "2024-05-28T17:01:54.731Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" }, +] + [[package]] name = "backports-zstd" version = "1.3.0" @@ -357,6 +378,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8d/ec/6247be6536668fe1c7dfae3eaa9c94b00b956b716957c0fc986ba78c3cc4/backports_zstd-1.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2524bd6777a828d5e7ccd7bd1a57f9e7007ae654fc2bd1bc1a207f6428674e4a", size = 299684, upload-time = "2025-12-29T17:28:04.856Z" }, ] +[[package]] +name = "beartype" +version = "0.22.9" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c7/94/1009e248bbfbab11397abca7193bea6626806be9a327d399810d523a07cb/beartype-0.22.9.tar.gz", hash = "sha256:8f82b54aa723a2848a56008d18875f91c1db02c32ef6a62319a002e3e25a975f", size = 1608866, upload-time = "2025-12-13T06:50:30.72Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2", size = 1333658, upload-time = "2025-12-13T06:50:28.266Z" }, +] + [[package]] name = "beautifulsoup4" version = "4.14.3" @@ -448,6 +478,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b5/d3/b07f8f125ac52bbee5dc00ef0d526f820f67321bf4184f915f17f50a4657/brotlicffi-1.2.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3832c66e00d6d82087f20a972b2fc03e21cd99ef22705225a6f8f418a9158ecc", size = 374730, upload-time = "2025-11-21T18:17:56.334Z" }, ] +[[package]] +name = "cachetools" +version = "6.2.4" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bc/1d/ede8680603f6016887c062a2cf4fc8fdba905866a3ab8831aa8aa651320c/cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607", size = 31731, upload-time = "2025-12-15T18:24:53.744Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2c/fc/1d7b80d0eb7b714984ce40efc78859c022cd930e402f599d8ca9e39c78a4/cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51", size = 11551, upload-time = "2025-12-15T18:24:52.332Z" }, +] + [[package]] name = "certifi" version = "2026.1.4" @@ -661,6 +700,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ae/5a/4f025bc751087833686892e17e7564828e409c43b632878afeae554870cd/click_log-0.4.0-py2.py3-none-any.whl", hash = "sha256:a43e394b528d52112af599f2fc9e4b7cf3c15f94e53581f74fa6867e68c91756" }, ] +[[package]] +name = "cloudpickle" +version = "3.1.2" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -1072,6 +1120,23 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30" }, ] +[[package]] +name = "cyclopts" +version = "4.5.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "attrs" }, + { name = "docstring-parser" }, + { name = "rich" }, + { name = "rich-rst" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/13/7b/663f3285c1ac0e5d0854bd9db2c87caa6fa3d1a063185e3394a6cdca9151/cyclopts-4.5.0.tar.gz", hash = "sha256:717ac4235548b58d500baf7e688aa4d024caf0ee68f61a012ffd5e29db3099f9", size = 161980, upload-time = "2026-01-16T02:07:16.171Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/12/a3/2e00fececc34a99ae3a5d5702a5dd29c5371e4ed016647301a2b9bcc1976/cyclopts-4.5.0-py3-none-any.whl", hash = "sha256:305b9aa90a9cd0916f0a450b43e50ad5df9c252680731a0719edfb9b20381bf5", size = 199772, upload-time = "2026-01-16T02:07:14.707Z" }, +] + [[package]] name = "dataclasses-json" version = "0.6.7" @@ -1085,6 +1150,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, ] +[[package]] +name = "diskcache" +version = "5.6.3" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19" }, +] + [[package]] name = "distro" version = "1.9.0" @@ -1094,6 +1168,46 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "docstring-parser" +version = "0.17.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.4" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, +] + +[[package]] +name = "email-validator" +version = "2.3.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, +] + [[package]] name = "et-xmlfile" version = "2.0.0" @@ -1108,7 +1222,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1132,6 +1246,54 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/51/37/b3ea9cd5558ff4cb51957caca2193981c6b0ff30bd0d2630ac62505d99d0/fake_useragent-2.2.0-py3-none-any.whl", hash = "sha256:67f35ca4d847b0d298187443aaf020413746e56acd985a611908c73dba2daa24", size = 161695, upload-time = "2025-04-14T15:32:17.732Z" }, ] +[[package]] +name = "fakeredis" +version = "2.33.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "redis" }, + { name = "sortedcontainers" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5f/f9/57464119936414d60697fcbd32f38909bb5688b616ae13de6e98384433e0/fakeredis-2.33.0.tar.gz", hash = "sha256:d7bc9a69d21df108a6451bbffee23b3eba432c21a654afc7ff2d295428ec5770", size = 175187, upload-time = "2025-12-16T19:45:52.269Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/6e/78/a850fed8aeef96d4a99043c90b818b2ed5419cd5b24a4049fd7cfb9f1471/fakeredis-2.33.0-py3-none-any.whl", hash = "sha256:de535f3f9ccde1c56672ab2fdd6a8efbc4f2619fc2f1acc87b8737177d71c965", size = 119605, upload-time = "2025-12-16T19:45:51.08Z" }, +] + +[package.optional-dependencies] +lua = [ + { name = "lupa" }, +] + +[[package]] +name = "fastmcp" +version = "2.14.4" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "authlib" }, + { name = "cyclopts" }, + { name = "exceptiongroup" }, + { name = "httpx" }, + { name = "jsonref" }, + { name = "jsonschema-path" }, + { name = "mcp" }, + { name = "openapi-pydantic" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "py-key-value-aio", extra = ["disk", "keyring", "memory"] }, + { name = "pydantic", extra = ["email"] }, + { name = "pydocket" }, + { name = "pyperclip" }, + { name = "python-dotenv" }, + { name = "rich" }, + { name = "uvicorn" }, + { name = "websockets" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/fd/a9/a57d5e5629ebd4ef82b495a7f8e346ce29ef80cc86b15c8c40570701b94d/fastmcp-2.14.4.tar.gz", hash = "sha256:c01f19845c2adda0a70d59525c9193be64a6383014c8d40ce63345ac664053ff", size = 8302239, upload-time = "2026-01-22T17:29:37.024Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3e/41/c4d407e2218fd60d84acb6cc5131d28ff876afecf325e3fd9d27b8318581/fastmcp-2.14.4-py3-none-any.whl", hash = "sha256:5858cff5e4c8ea8107f9bca2609d71d6256e0fce74495912f6e51625e466c49a", size = 417788, upload-time = "2026-01-22T17:29:35.159Z" }, +] + [[package]] name = "fastuuid" version = "0.14.0" @@ -1763,6 +1925,51 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "jaraco-classes" +version = "3.4.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "more-itertools" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" }, +] + +[[package]] +name = "jaraco-context" +version = "6.1.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "backports-tarfile", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cb/9c/a788f5bb29c61e456b8ee52ce76dbdd32fd72cd73dd67bc95f42c7a8d13c/jaraco_context-6.1.0.tar.gz", hash = "sha256:129a341b0a85a7db7879e22acd66902fda67882db771754574338898b2d5d86f", size = 15850, upload-time = "2026-01-13T02:53:53.847Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8d/48/aa685dbf1024c7bd82bede569e3a85f82c32fd3d79ba5fea578f0159571a/jaraco_context-6.1.0-py3-none-any.whl", hash = "sha256:a43b5ed85815223d0d3cfdb6d7ca0d2bc8946f28f30b6f3216bda070f68badda", size = 7065, upload-time = "2026-01-13T02:53:53.031Z" }, +] + +[[package]] +name = "jaraco-functools" +version = "4.4.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "more-itertools" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl", hash = "sha256:9eec1e36f45c818d9bf307c8948eb03b2b56cd44087b3cdc989abca1f20b9176", size = 10481, upload-time = "2025-12-21T09:29:42.27Z" }, +] + +[[package]] +name = "jeepney" +version = "0.9.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -1902,6 +2109,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, ] +[[package]] +name = "jsonref" +version = "1.1.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/aa/0d/c1f3277e90ccdb50d33ed5ba1ec5b3f0a242ed8c1b1a85d3afeb68464dca/jsonref-1.1.0.tar.gz", hash = "sha256:32fe8e1d85af0fdefbebce950af85590b22b60f9e95443176adbde4e1ecea552", size = 8814, upload-time = "2023-01-16T16:10:04.455Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl", hash = "sha256:590dc7773df6c21cbf948b5dac07a72a251db28b0238ceecce0a2abfa8ec30a9", size = 9425, upload-time = "2023-01-16T16:10:02.255Z" }, +] + [[package]] name = "jsonschema" version = "4.26.0" @@ -1917,6 +2133,21 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, ] +[[package]] +name = "jsonschema-path" +version = "0.3.4" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "pathable" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "requests" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/6e/45/41ebc679c2a4fced6a722f624c18d658dee42612b83ea24c1caf7c0eb3a8/jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001", size = 11159, upload-time = "2025-01-24T14:33:16.547Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cb/58/3485da8cb93d2f393bce453adeef16896751f14ba3e2024bc21dc9597646/jsonschema_path-0.3.4-py3-none-any.whl", hash = "sha256:f502191fdc2b22050f9a81c9237be9d27145b9001c55842bece5e94e382e52f8", size = 14810, upload-time = "2025-01-24T14:33:14.652Z" }, +] + [[package]] name = "jsonschema-specifications" version = "2025.9.1" @@ -1929,6 +2160,24 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] +[[package]] +name = "keyring" +version = "25.7.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "importlib-metadata", marker = "python_full_version < '3.12'" }, + { name = "jaraco-classes" }, + { name = "jaraco-context" }, + { name = "jaraco-functools" }, + { name = "jeepney", marker = "sys_platform == 'linux'" }, + { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, + { name = "secretstorage", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" }, +] + [[package]] name = "kiwisolver" version = "1.4.9" @@ -2347,6 +2596,80 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/59/73/8d100c4e48935f6a381df60f894ca9c063ea412ce354fbe7a17770ad4092/litellm-1.81.1-py3-none-any.whl", hash = "sha256:503512a8a7f3cddf9d8fed6182c14f1e77c5655635fe67b09efb09c75234bb87", size = 11795146, upload-time = "2026-01-21T12:55:55.613Z" }, ] +[[package]] +name = "lupa" +version = "2.6" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b8/1c/191c3e6ec6502e3dbe25a53e27f69a5daeac3e56de1f73c0138224171ead/lupa-2.6.tar.gz", hash = "sha256:9a770a6e89576be3447668d7ced312cd6fd41d3c13c2462c9dc2c2ab570e45d9", size = 7240282, upload-time = "2025-10-24T07:20:29.738Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a1/15/713cab5d0dfa4858f83b99b3e0329072df33dc14fc3ebbaa017e0f9755c4/lupa-2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b3dabda836317e63c5ad052826e156610f356a04b3003dfa0dbe66b5d54d671", size = 954828, upload-time = "2025-10-24T07:17:15.726Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2e/71/704740cbc6e587dd6cc8dabf2f04820ac6a671784e57cc3c29db795476db/lupa-2.6-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8726d1c123bbe9fbb974ce29825e94121824e66003038ff4532c14cc2ed0c51c", size = 1919259, upload-time = "2025-10-24T07:17:18.586Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/eb/18/f248341c423c5d48837e35584c6c3eb4acab7e722b6057d7b3e28e42dae8/lupa-2.6-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:f4e159e7d814171199b246f9235ca8961f6461ea8c1165ab428afa13c9289a94", size = 984998, upload-time = "2025-10-24T07:17:20.428Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/44/1e/8a4bd471e018aad76bcb9455d298c2c96d82eced20f2ae8fcec8cd800948/lupa-2.6-cp310-cp310-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:202160e80dbfddfb79316692a563d843b767e0f6787bbd1c455f9d54052efa6c", size = 1174871, upload-time = "2025-10-24T07:17:22.755Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2a/5c/3a3f23fd6a91b0986eea1ceaf82ad3f9b958fe3515a9981fb9c4eb046c8b/lupa-2.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5deede7c5b36ab64f869dae4831720428b67955b0bb186c8349cf6ea121c852b", size = 1057471, upload-time = "2025-10-24T07:17:24.908Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/45/ac/01be1fed778fb0c8f46ee8cbe344e4d782f6806fac12717f08af87aa4355/lupa-2.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86f04901f920bbf7c0cac56807dc9597e42347123e6f1f3ca920f15f54188ce5", size = 2100592, upload-time = "2025-10-24T07:17:27.089Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3f/6c/1a05bb873e30830f8574e10cd0b4cdbc72e9dbad2a09e25810b5e3b1f75d/lupa-2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6deef8f851d6afb965c84849aa5b8c38856942df54597a811ce0369ced678610", size = 1081396, upload-time = "2025-10-24T07:17:29.064Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a2/c2/a19dd80d6dc98b39bbf8135b8198e38aa7ca3360b720eac68d1d7e9286b5/lupa-2.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:21f2b5549681c2a13b1170a26159d30875d367d28f0247b81ca347222c755038", size = 1192007, upload-time = "2025-10-24T07:17:31.362Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/4f/43/e1b297225c827f55752e46fdbfb021c8982081b0f24490e42776ea69ae3b/lupa-2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:66eea57630eab5e6f49fdc5d7811c0a2a41f2011be4ea56a087ea76112011eb7", size = 2196661, upload-time = "2025-10-24T07:17:33.484Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2e/8f/2272d429a7fa9dc8dbd6e9c5c9073a03af6007eb22a4c78829fec6a34b80/lupa-2.6-cp310-cp310-win32.whl", hash = "sha256:60a403de8cab262a4fe813085dd77010effa6e2eb1886db2181df803140533b1", size = 1412738, upload-time = "2025-10-24T07:17:35.11Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/35/2a/1708911271dd49ad87b4b373b5a4b0e0a0516d3d2af7b76355946c7ee171/lupa-2.6-cp310-cp310-win_amd64.whl", hash = "sha256:e4656a39d93dfa947cf3db56dc16c7916cb0cc8024acd3a952071263f675df64", size = 1656898, upload-time = "2025-10-24T07:17:36.949Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ca/29/1f66907c1ebf1881735afa695e646762c674f00738ebf66d795d59fc0665/lupa-2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6d988c0f9331b9f2a5a55186701a25444ab10a1432a1021ee58011499ecbbdd5", size = 962875, upload-time = "2025-10-24T07:17:39.107Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e6/67/4a748604be360eb9c1c215f6a0da921cd1a2b44b2c5951aae6fb83019d3a/lupa-2.6-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:ebe1bbf48259382c72a6fe363dea61a0fd6fe19eab95e2ae881e20f3654587bf", size = 1935390, upload-time = "2025-10-24T07:17:41.427Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ac/0c/8ef9ee933a350428b7bdb8335a37ef170ab0bb008bbf9ca8f4f4310116b6/lupa-2.6-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:a8fcee258487cf77cdd41560046843bb38c2e18989cd19671dd1e2596f798306", size = 992193, upload-time = "2025-10-24T07:17:43.231Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/65/46/e6c7facebdb438db8a65ed247e56908818389c1a5abbf6a36aab14f1057d/lupa-2.6-cp311-cp311-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:561a8e3be800827884e767a694727ed8482d066e0d6edfcbf423b05e63b05535", size = 1165844, upload-time = "2025-10-24T07:17:45.437Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1c/26/9f1154c6c95f175ccbf96aa96c8f569c87f64f463b32473e839137601a8b/lupa-2.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af880a62d47991cae78b8e9905c008cbfdc4a3a9723a66310c2634fc7644578c", size = 1048069, upload-time = "2025-10-24T07:17:47.181Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/68/67/2cc52ab73d6af81612b2ea24c870d3fa398443af8e2875e5befe142398b1/lupa-2.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80b22923aa4023c86c0097b235615f89d469a0c4eee0489699c494d3367c4c85", size = 2079079, upload-time = "2025-10-24T07:17:49.755Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2e/dc/f843f09bbf325f6e5ee61730cf6c3409fc78c010d968c7c78acba3019ca7/lupa-2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:153d2cc6b643f7efb9cfc0c6bb55ec784d5bac1a3660cfc5b958a7b8f38f4a75", size = 1071428, upload-time = "2025-10-24T07:17:51.991Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2e/60/37533a8d85bf004697449acb97ecdacea851acad28f2ad3803662487dd2a/lupa-2.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3fa8777e16f3ded50b72967dc17e23f5a08e4f1e2c9456aff2ebdb57f5b2869f", size = 1181756, upload-time = "2025-10-24T07:17:53.752Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e4/f2/cf29b20dbb4927b6a3d27c339ac5d73e74306ecc28c8e2c900b2794142ba/lupa-2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8dbdcbe818c02a2f56f5ab5ce2de374dab03e84b25266cfbaef237829bc09b3f", size = 2175687, upload-time = "2025-10-24T07:17:56.228Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/94/7c/050e02f80c7131b63db1474bff511e63c545b5a8636a24cbef3fc4da20b6/lupa-2.6-cp311-cp311-win32.whl", hash = "sha256:defaf188fde8f7a1e5ce3a5e6d945e533b8b8d547c11e43b96c9b7fe527f56dc", size = 1412592, upload-time = "2025-10-24T07:17:59.062Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/6f/9a/6f2af98aa5d771cea661f66c8eb8f53772ec1ab1dfbce24126cfcd189436/lupa-2.6-cp311-cp311-win_amd64.whl", hash = "sha256:9505ae600b5c14f3e17e70f87f88d333717f60411faca1ddc6f3e61dce85fa9e", size = 1669194, upload-time = "2025-10-24T07:18:01.647Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/94/86/ce243390535c39d53ea17ccf0240815e6e457e413e40428a658ea4ee4b8d/lupa-2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47ce718817ef1cc0c40d87c3d5ae56a800d61af00fbc0fad1ca9be12df2f3b56", size = 951707, upload-time = "2025-10-24T07:18:03.884Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/86/85/cedea5e6cbeb54396fdcc55f6b741696f3f036d23cfaf986d50d680446da/lupa-2.6-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:7aba985b15b101495aa4b07112cdc08baa0c545390d560ad5cfde2e9e34f4d58", size = 1916703, upload-time = "2025-10-24T07:18:05.6Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/24/be/3d6b5f9a8588c01a4d88129284c726017b2089f3a3fd3ba8bd977292fea0/lupa-2.6-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:b766f62f95b2739f2248977d29b0722e589dcf4f0ccfa827ccbd29f0148bd2e5", size = 985152, upload-time = "2025-10-24T07:18:08.561Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/eb/23/9f9a05beee5d5dce9deca4cb07c91c40a90541fc0a8e09db4ee670da550f/lupa-2.6-cp312-cp312-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:00a934c23331f94cb51760097ebfab14b005d55a6b30a2b480e3c53dd2fa290d", size = 1159599, upload-time = "2025-10-24T07:18:10.346Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/40/4e/e7c0583083db9d7f1fd023800a9767d8e4391e8330d56c2373d890ac971b/lupa-2.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21de9f38bd475303e34a042b7081aabdf50bd9bafd36ce4faea2f90fd9f15c31", size = 1038686, upload-time = "2025-10-24T07:18:12.112Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1c/9f/5a4f7d959d4feba5e203ff0c31889e74d1ca3153122be4a46dca7d92bf7c/lupa-2.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf3bda96d3fc41237e964a69c23647d50d4e28421111360274d4799832c560e9", size = 2071956, upload-time = "2025-10-24T07:18:14.572Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/92/34/2f4f13ca65d01169b1720176aedc4af17bc19ee834598c7292db232cb6dc/lupa-2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a76ead245da54801a81053794aa3975f213221f6542d14ec4b859ee2e7e0323", size = 1057199, upload-time = "2025-10-24T07:18:16.379Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/35/2a/5f7d2eebec6993b0dcd428e0184ad71afb06a45ba13e717f6501bfed1da3/lupa-2.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8dd0861741caa20886ddbda0a121d8e52fb9b5bb153d82fa9bba796962bf30e8", size = 1173693, upload-time = "2025-10-24T07:18:18.153Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e4/29/089b4d2f8e34417349af3904bb40bec40b65c8731f45e3fd8d497ca573e5/lupa-2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:239e63948b0b23023f81d9a19a395e768ed3da6a299f84e7963b8f813f6e3f9c", size = 2164394, upload-time = "2025-10-24T07:18:20.403Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f3/1b/79c17b23c921f81468a111cad843b076a17ef4b684c4a8dff32a7969c3f0/lupa-2.6-cp312-cp312-win32.whl", hash = "sha256:325894e1099499e7a6f9c351147661a2011887603c71086d36fe0f964d52d1ce", size = 1420647, upload-time = "2025-10-24T07:18:23.368Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b8/15/5121e68aad3584e26e1425a5c9a79cd898f8a152292059e128c206ee817c/lupa-2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c735a1ce8ee60edb0fe71d665f1e6b7c55c6021f1d340eb8c865952c602cd36f", size = 1688529, upload-time = "2025-10-24T07:18:25.523Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/28/1d/21176b682ca5469001199d8b95fa1737e29957a3d185186e7a8b55345f2e/lupa-2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:663a6e58a0f60e7d212017d6678639ac8df0119bc13c2145029dcba084391310", size = 947232, upload-time = "2025-10-24T07:18:27.878Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ce/4c/d327befb684660ca13cf79cd1f1d604331808f9f1b6fb6bf57832f8edf80/lupa-2.6-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:d1f5afda5c20b1f3217a80e9bc1b77037f8a6eb11612fd3ada19065303c8f380", size = 1908625, upload-time = "2025-10-24T07:18:29.944Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/66/8e/ad22b0a19454dfd08662237a84c792d6d420d36b061f239e084f29d1a4f3/lupa-2.6-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:26f2b3c085fe76e9119e48c1013c1cccdc1f51585d456858290475aa38e7089e", size = 981057, upload-time = "2025-10-24T07:18:31.553Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5c/48/74859073ab276bd0566c719f9ca0108b0cfc1956ca0d68678d117d47d155/lupa-2.6-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:60d2f902c7b96fb8ab98493dcff315e7bb4d0b44dc9dd76eb37de575025d5685", size = 1156227, upload-time = "2025-10-24T07:18:33.981Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/09/6c/0e9ded061916877253c2266074060eb71ed99fb21d73c8c114a76725bce2/lupa-2.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a02d25dee3a3250967c36590128d9220ae02f2eda166a24279da0b481519cbff", size = 1035752, upload-time = "2025-10-24T07:18:36.32Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/dd/ef/f8c32e454ef9f3fe909f6c7d57a39f950996c37a3deb7b391fec7903dab7/lupa-2.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6eae1ee16b886b8914ff292dbefbf2f48abfbdee94b33a88d1d5475e02423203", size = 2069009, upload-time = "2025-10-24T07:18:38.072Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/53/dc/15b80c226a5225815a890ee1c11f07968e0aba7a852df41e8ae6fe285063/lupa-2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0edd5073a4ee74ab36f74fe61450148e6044f3952b8d21248581f3c5d1a58be", size = 1056301, upload-time = "2025-10-24T07:18:40.165Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/31/14/2086c1425c985acfb30997a67e90c39457122df41324d3c179d6ee2292c6/lupa-2.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0c53ee9f22a8a17e7d4266ad48e86f43771951797042dd51d1494aaa4f5f3f0a", size = 1170673, upload-time = "2025-10-24T07:18:42.426Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/10/e5/b216c054cf86576c0191bf9a9f05de6f7e8e07164897d95eea0078dca9b2/lupa-2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:de7c0f157a9064a400d828789191a96da7f4ce889969a588b87ec80de9b14772", size = 2162227, upload-time = "2025-10-24T07:18:46.112Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/59/2f/33ecb5bedf4f3bc297ceacb7f016ff951331d352f58e7e791589609ea306/lupa-2.6-cp313-cp313-win32.whl", hash = "sha256:ee9523941ae0a87b5b703417720c5d78f72d2f5bc23883a2ea80a949a3ed9e75", size = 1419558, upload-time = "2025-10-24T07:18:48.371Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f9/b4/55e885834c847ea610e111d87b9ed4768f0afdaeebc00cd46810f25029f6/lupa-2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b1335a5835b0a25ebdbc75cf0bda195e54d133e4d994877ef025e218c2e59db9", size = 1683424, upload-time = "2025-10-24T07:18:50.976Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/66/9d/d9427394e54d22a35d1139ef12e845fd700d4872a67a34db32516170b746/lupa-2.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dcb6d0a3264873e1653bc188499f48c1fb4b41a779e315eba45256cfe7bc33c1", size = 953818, upload-time = "2025-10-24T07:18:53.378Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/10/41/27bbe81953fb2f9ecfced5d9c99f85b37964cfaf6aa8453bb11283983721/lupa-2.6-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:a37e01f2128f8c36106726cb9d360bac087d58c54b4522b033cc5691c584db18", size = 1915850, upload-time = "2025-10-24T07:18:55.259Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a3/98/f9ff60db84a75ba8725506bbf448fb085bc77868a021998ed2a66d920568/lupa-2.6-cp314-cp314-macosx_11_0_x86_64.whl", hash = "sha256:458bd7e9ff3c150b245b0fcfbb9bd2593d1152ea7f0a7b91c1d185846da033fe", size = 982344, upload-time = "2025-10-24T07:18:57.05Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/41/f7/f39e0f1c055c3b887d86b404aaf0ca197b5edfd235a8b81b45b25bac7fc3/lupa-2.6-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:052ee82cac5206a02df77119c325339acbc09f5ce66967f66a2e12a0f3211cad", size = 1156543, upload-time = "2025-10-24T07:18:59.251Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9e/9c/59e6cffa0d672d662ae17bd7ac8ecd2c89c9449dee499e3eb13ca9cd10d9/lupa-2.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96594eca3c87dd07938009e95e591e43d554c1dbd0385be03c100367141db5a8", size = 1047974, upload-time = "2025-10-24T07:19:01.449Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/23/c6/a04e9cef7c052717fcb28fb63b3824802488f688391895b618e39be0f684/lupa-2.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8faddd9d198688c8884091173a088a8e920ecc96cda2ffed576a23574c4b3f6", size = 2073458, upload-time = "2025-10-24T07:19:03.369Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e6/10/824173d10f38b51fc77785228f01411b6ca28826ce27404c7c912e0e442c/lupa-2.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:daebb3a6b58095c917e76ba727ab37b27477fb926957c825205fbda431552134", size = 1067683, upload-time = "2025-10-24T07:19:06.2Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b6/dc/9692fbcf3c924d9c4ece2d8d2f724451ac2e09af0bd2a782db1cef34e799/lupa-2.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f3154e68972befe0f81564e37d8142b5d5d79931a18309226a04ec92487d4ea3", size = 1171892, upload-time = "2025-10-24T07:19:08.544Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/84/ff/e318b628d4643c278c96ab3ddea07fc36b075a57383c837f5b11e537ba9d/lupa-2.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e4dadf77b9fedc0bfa53417cc28dc2278a26d4cbd95c29f8927ad4d8fe0a7ef9", size = 2166641, upload-time = "2025-10-24T07:19:10.485Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/12/f7/a6f9ec2806cf2d50826980cdb4b3cffc7691dc6f95e13cc728846d5cb793/lupa-2.6-cp314-cp314-win32.whl", hash = "sha256:cb34169c6fa3bab3e8ac58ca21b8a7102f6a94b6a5d08d3636312f3f02fafd8f", size = 1456857, upload-time = "2025-10-24T07:19:37.989Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c5/de/df71896f25bdc18360fdfa3b802cd7d57d7fede41a0e9724a4625b412c85/lupa-2.6-cp314-cp314-win_amd64.whl", hash = "sha256:b74f944fe46c421e25d0f8692aef1e842192f6f7f68034201382ac440ef9ea67", size = 1731191, upload-time = "2025-10-24T07:19:40.281Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/47/3c/a1f23b01c54669465f5f4c4083107d496fbe6fb45998771420e9aadcf145/lupa-2.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0e21b716408a21ab65723f8841cf7f2f37a844b7a965eeabb785e27fca4099cf", size = 999343, upload-time = "2025-10-24T07:19:12.519Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c5/6d/501994291cb640bfa2ccf7f554be4e6914afa21c4026bd01bff9ca8aac57/lupa-2.6-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:589db872a141bfff828340079bbdf3e9a31f2689f4ca0d88f97d9e8c2eae6142", size = 2000730, upload-time = "2025-10-24T07:19:14.869Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/53/a5/457ffb4f3f20469956c2d4c4842a7675e884efc895b2f23d126d23e126cc/lupa-2.6-cp314-cp314t-macosx_11_0_x86_64.whl", hash = "sha256:cd852a91a4a9d4dcbb9a58100f820a75a425703ec3e3f049055f60b8533b7953", size = 1021553, upload-time = "2025-10-24T07:19:17.123Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/51/6b/36bb5a5d0960f2a5c7c700e0819abb76fd9bf9c1d8a66e5106416d6e9b14/lupa-2.6-cp314-cp314t-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:0334753be028358922415ca97a64a3048e4ed155413fc4eaf87dd0a7e2752983", size = 1133275, upload-time = "2025-10-24T07:19:20.51Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/19/86/202ff4429f663013f37d2229f6176ca9f83678a50257d70f61a0a97281bf/lupa-2.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:661d895cd38c87658a34780fac54a690ec036ead743e41b74c3fb81a9e65a6aa", size = 1038441, upload-time = "2025-10-24T07:19:22.509Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a7/42/d8125f8e420714e5b52e9c08d88b5329dfb02dcca731b4f21faaee6cc5b5/lupa-2.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aa58454ccc13878cc177c62529a2056be734da16369e451987ff92784994ca7", size = 2058324, upload-time = "2025-10-24T07:19:24.979Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2b/2c/47bf8b84059876e877a339717ddb595a4a7b0e8740bacae78ba527562e1c/lupa-2.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1425017264e470c98022bba8cff5bd46d054a827f5df6b80274f9cc71dafd24f", size = 1060250, upload-time = "2025-10-24T07:19:27.262Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c2/06/d88add2b6406ca1bdec99d11a429222837ca6d03bea42ca75afa169a78cb/lupa-2.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:224af0532d216e3105f0a127410f12320f7c5f1aa0300bdf9646b8d9afb0048c", size = 1151126, upload-time = "2025-10-24T07:19:29.522Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b4/a0/89e6a024c3b4485b89ef86881c9d55e097e7cb0bdb74efb746f2fa6a9a76/lupa-2.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9abb98d5a8fd27c8285302e82199f0e56e463066f88f619d6594a450bf269d80", size = 2153693, upload-time = "2025-10-24T07:19:31.379Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b6/36/a0f007dc58fc1bbf51fb85dcc82fcb1f21b8c4261361de7dab0e3d8521ef/lupa-2.6-cp314-cp314t-win32.whl", hash = "sha256:1849efeba7a8f6fb8aa2c13790bee988fd242ae404bd459509640eeea3d1e291", size = 1590104, upload-time = "2025-10-24T07:19:33.514Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7d/5e/db903ce9cf82c48d6b91bf6d63ae4c8d0d17958939a4e04ba6b9f38b8643/lupa-2.6-cp314-cp314t-win_amd64.whl", hash = "sha256:fc1498d1a4fc028bc521c26d0fad4ca00ed63b952e32fb95949bda76a04bad52", size = 1913818, upload-time = "2025-10-24T07:19:36.039Z" }, +] + [[package]] name = "lxml" version = "5.4.0" @@ -2627,6 +2950,31 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/73/e4/6d6f14b2a759c622f191b2d67e9075a3f56aaccb3be4bb9bb6890030d0a0/matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2", size = 8713867, upload-time = "2025-12-10T22:56:48.954Z" }, ] +[[package]] +name = "mcp" +version = "1.25.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d5/2d/649d80a0ecf6a1f82632ca44bec21c0461a9d9fc8934d38cb5b319f2db5e/mcp-1.25.0.tar.gz", hash = "sha256:56310361ebf0364e2d438e5b45f7668cbb124e158bb358333cd06e49e83a6802", size = 605387, upload-time = "2025-12-19T10:19:56.985Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e2/fc/6dc7659c2ae5ddf280477011f4213a74f806862856b796ef08f028e664bf/mcp-1.25.0-py3-none-any.whl", hash = "sha256:b37c38144a666add0862614cc79ec276e97d72aa8ca26d622818d4e278b9721a", size = 233076, upload-time = "2025-12-19T10:19:55.416Z" }, +] + [[package]] name = "mdit-py-plugins" version = "0.5.0" @@ -2648,6 +2996,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] +[[package]] +name = "more-itertools" +version = "10.8.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, +] + [[package]] name = "multidict" version = "6.7.0" @@ -3059,6 +3416,18 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b5/df/c306f7375d42bafb379934c2df4c2fa3964656c8c782bac75ee10c102818/openai-2.15.0-py3-none-any.whl", hash = "sha256:6ae23b932cd7230f7244e52954daa6602716d6b9bf235401a107af731baea6c3", size = 1067879, upload-time = "2026-01-09T22:10:06.446Z" }, ] +[[package]] +name = "openapi-pydantic" +version = "0.5.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892, upload-time = "2025-01-08T19:29:27.083Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146", size = 96381, upload-time = "2025-01-08T19:29:25.275Z" }, +] + [[package]] name = "openpyxl" version = "3.1.5" @@ -3071,6 +3440,75 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, ] +[[package]] +name = "opentelemetry-api" +version = "1.39.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, +] + +[[package]] +name = "opentelemetry-exporter-prometheus" +version = "0.60b1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-sdk" }, + { name = "prometheus-client" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/14/39/7dafa6fff210737267bed35a8855b6ac7399b9e582b8cf1f25f842517012/opentelemetry_exporter_prometheus-0.60b1.tar.gz", hash = "sha256:a4011b46906323f71724649d301b4dc188aaa068852e814f4df38cc76eac616b", size = 14976, upload-time = "2025-12-11T13:32:42.944Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9b/0d/4be6bf5477a3eb3d917d2f17d3c0b6720cd6cb97898444a61d43cc983f5c/opentelemetry_exporter_prometheus-0.60b1-py3-none-any.whl", hash = "sha256:49f59178de4f4590e3cef0b8b95cf6e071aae70e1f060566df5546fad773b8fd", size = 13019, upload-time = "2025-12-11T13:32:23.974Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation" +version = "0.60b1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "packaging" }, + { name = "wrapt" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096, upload-time = "2025-12-11T13:35:33.067Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.39.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.60b1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, +] + [[package]] name = "orjson" version = "3.11.5" @@ -3236,6 +3674,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5c/31/5371fb36ec6ec3b4b1ae1784dd5254e2c7b85d0e0d34dd371933ffde2c53/patchright-1.57.2-py3-none-win_arm64.whl", hash = "sha256:830173d31c0a9eed6c03192e191dc007f30f05bc580764860cbd0001431f6f01", size = 32816218, upload-time = "2025-12-30T15:34:01.582Z" }, ] +[[package]] +name = "pathable" +version = "0.4.4" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/67/93/8f2c2075b180c12c1e9f6a09d1a985bc2036906b13dff1d8917e395f2048/pathable-0.4.4.tar.gz", hash = "sha256:6905a3cd17804edfac7875b5f6c9142a218c7caef78693c2dbbbfbac186d88b2", size = 8124, upload-time = "2025-01-10T18:43:13.247Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7d/eb/b6260b31b1a96386c0a880edebe26f89669098acea8e0318bff6adb378fd/pathable-0.4.4-py3-none-any.whl", hash = "sha256:5ae9e94793b6ef5a4cbe0a7ce9dbbefc1eec38df253763fd0aeeacf2762dbbc2", size = 9592, upload-time = "2025-01-10T18:43:11.88Z" }, +] + [[package]] name = "pathspec" version = "1.0.3" @@ -3245,6 +3692,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, ] +[[package]] +name = "pathvalidate" +version = "3.3.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/fa/2a/52a8da6fe965dea6192eb716b357558e103aea0a1e9a8352ad575a8406ca/pathvalidate-3.3.1.tar.gz", hash = "sha256:b18c07212bfead624345bb8e1d6141cdcf15a39736994ea0b94035ad2b1ba177", size = 63262, upload-time = "2025-06-15T09:07:20.736Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9a/70/875f4a23bfc4731703a5835487d0d2fb999031bd415e7d17c0ae615c18b7/pathvalidate-3.3.1-py3-none-any.whl", hash = "sha256:5263baab691f8e1af96092fa5137ee17df5bdfbd6cff1fcac4d6ef4bc2e1735f", size = 24305, upload-time = "2025-06-15T09:07:19.117Z" }, +] + [[package]] name = "pillow" version = "12.1.0" @@ -3343,6 +3799,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2d/71/64e9b1c7f04ae0027f788a248e6297d7fcc29571371fe7d45495a78172c0/pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19", size = 7029809, upload-time = "2026-01-02T09:13:26.541Z" }, ] +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + [[package]] name = "playwright" version = "1.57.0" @@ -3371,6 +3836,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "prometheus-client" +version = "0.24.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616, upload-time = "2026-01-14T15:26:26.965Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057, upload-time = "2026-01-14T15:26:24.42Z" }, +] + [[package]] name = "propcache" version = "0.4.1" @@ -3513,6 +3987,47 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3e/73/2ce007f4198c80fcf2cb24c169884f833fe93fbc03d55d302627b094ee91/psutil-7.2.1-cp37-abi3-win_arm64.whl", hash = "sha256:0d67c1822c355aa6f7314d92018fb4268a76668a536f133599b91edd48759442", size = 133836, upload-time = "2025-12-29T08:26:43.086Z" }, ] +[[package]] +name = "py-key-value-aio" +version = "0.3.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "beartype" }, + { name = "py-key-value-shared" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/93/ce/3136b771dddf5ac905cc193b461eb67967cf3979688c6696e1f2cdcde7ea/py_key_value_aio-0.3.0.tar.gz", hash = "sha256:858e852fcf6d696d231266da66042d3355a7f9871650415feef9fca7a6cd4155", size = 50801, upload-time = "2025-11-17T16:50:04.711Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/99/10/72f6f213b8f0bce36eff21fda0a13271834e9eeff7f9609b01afdc253c79/py_key_value_aio-0.3.0-py3-none-any.whl", hash = "sha256:1c781915766078bfd608daa769fefb97e65d1d73746a3dfb640460e322071b64", size = 96342, upload-time = "2025-11-17T16:50:03.801Z" }, +] + +[package.optional-dependencies] +disk = [ + { name = "diskcache" }, + { name = "pathvalidate" }, +] +keyring = [ + { name = "keyring" }, +] +memory = [ + { name = "cachetools" }, +] +redis = [ + { name = "redis" }, +] + +[[package]] +name = "py-key-value-shared" +version = "0.3.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "beartype" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7b/e4/1971dfc4620a3a15b4579fe99e024f5edd6e0967a71154771a059daff4db/py_key_value_shared-0.3.0.tar.gz", hash = "sha256:8fdd786cf96c3e900102945f92aa1473138ebe960ef49da1c833790160c28a4b", size = 11666, upload-time = "2025-11-17T16:50:06.849Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/51/e4/b8b0a03ece72f47dce2307d36e1c34725b7223d209fc679315ffe6a4e2c3/py_key_value_shared-0.3.0-py3-none-any.whl", hash = "sha256:5b0efba7ebca08bb158b1e93afc2f07d30b8f40c2fc12ce24a4c0d84f42f9298", size = 19560, upload-time = "2025-11-17T16:50:05.954Z" }, +] + [[package]] name = "py7zr" version = "1.1.2" @@ -3655,6 +4170,11 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, ] +[package.optional-dependencies] +email = [ + { name = "email-validator" }, +] + [[package]] name = "pydantic-core" version = "2.41.5" @@ -3787,6 +4307,30 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] +[[package]] +name = "pydocket" +version = "0.16.6" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "cloudpickle" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "fakeredis", extra = ["lua"] }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-prometheus" }, + { name = "opentelemetry-instrumentation" }, + { name = "prometheus-client" }, + { name = "py-key-value-aio", extra = ["memory", "redis"] }, + { name = "python-json-logger" }, + { name = "redis" }, + { name = "rich" }, + { name = "typer" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/72/00/26befe5f58df7cd1aeda4a8d10bc7d1908ffd86b80fd995e57a2a7b3f7bd/pydocket-0.16.6.tar.gz", hash = "sha256:b96c96ad7692827214ed4ff25fcf941ec38371314db5dcc1ae792b3e9d3a0294", size = 299054, upload-time = "2026-01-09T22:09:15.405Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0a/3f/7483e5a6dc6326b6e0c640619b5c5bd1d6e3c20e54d58f5fb86267cef00e/pydocket-0.16.6-py3-none-any.whl", hash = "sha256:683d21e2e846aa5106274e7d59210331b242d7fb0dce5b08d3b82065663ed183", size = 67697, upload-time = "2026-01-09T22:09:13.436Z" }, +] + [[package]] name = "pyee" version = "13.0.0" @@ -3808,17 +4352,31 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + [[package]] name = "pymdown-extensions" -version = "10.20" +version = "10.20.1" source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] -sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3e/35/e3814a5b7df295df69d035cfb8aab78b2967cdf11fcfae7faed726b66664/pymdown_extensions-10.20.tar.gz", hash = "sha256:5c73566ab0cf38c6ba084cb7c5ea64a119ae0500cce754ccb682761dfea13a52", size = 852774, upload-time = "2025-12-31T19:59:42.211Z" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1e/6c/9e370934bfa30e889d12e61d0dae009991294f40055c238980066a7fbd83/pymdown_extensions-10.20.1.tar.gz", hash = "sha256:e7e39c865727338d434b55f1dd8da51febcffcaebd6e1a0b9c836243f660740a", size = 852860, upload-time = "2026-01-24T05:56:56.758Z" } wheels = [ - { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ea/10/47caf89cbb52e5bb764696fd52a8c591a2f0e851a93270c05a17f36000b5/pymdown_extensions-10.20-py3-none-any.whl", hash = "sha256:ea9e62add865da80a271d00bfa1c0fa085b20d133fb3fc97afdc88e682f60b2f", size = 268733, upload-time = "2025-12-31T19:59:40.652Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/40/6d/b6ee155462a0156b94312bdd82d2b92ea56e909740045a87ccb98bf52405/pymdown_extensions-10.20.1-py3-none-any.whl", hash = "sha256:24af7feacbca56504b313b7b418c4f5e1317bb5fea60f03d57be7fcc40912aa0", size = 268768, upload-time = "2026-01-24T05:56:54.537Z" }, ] [[package]] @@ -3858,6 +4416,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] +[[package]] +name = "pyperclip" +version = "1.11.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e8/52/d87eba7cb129b81563019d1679026e7a112ef76855d6159d24754dbd2a51/pyperclip-1.11.0.tar.gz", hash = "sha256:244035963e4428530d9e3a6101a1ef97209c6825edab1567beac148ccc1db1b6", size = 12185, upload-time = "2025-09-26T14:40:37.245Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" }, +] + [[package]] name = "pyppmd" version = "1.3.1" @@ -4006,6 +4573,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] +[[package]] +name = "python-json-logger" +version = "4.0.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, +] + [[package]] name = "python-markdown-math" version = "0.9" @@ -4018,6 +4594,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/eb/68/ecf3535c40845de2efd8ac2d092dd5fca0868219fa3684d9e58ef7abeece/python_markdown_math-0.9-py3-none-any.whl", hash = "sha256:ac9932df517a5c0f6d01c56e7a44d065eca4a420893ac45f7a6937c67cb41e86", size = 6046, upload-time = "2025-04-10T10:10:30.318Z" }, ] +[[package]] +name = "python-multipart" +version = "0.0.21" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196, upload-time = "2025-12-17T09:24:22.446Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" }, +] + [[package]] name = "python-pptx" version = "1.0.2" @@ -4042,6 +4627,37 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -4128,18 +4744,30 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/62/fc/ab37559419ca36dd8dd317c3a98395ed4dcee2beeb28bf6059b972906727/rarfile-4.2-py3-none-any.whl", hash = "sha256:8757e1e3757e32962e229cab2432efc1f15f210823cc96ccba0f6a39d17370c9", size = 29052, upload-time = "2024-04-03T17:10:52.632Z" }, ] +[[package]] +name = "redis" +version = "7.1.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/43/c8/983d5c6579a411d8a99bc5823cc5712768859b5ce2c8afe1a65b37832c81/redis-7.1.0.tar.gz", hash = "sha256:b1cc3cfa5a2cb9c2ab3ba700864fb0ad75617b41f01352ce5779dabf6d5f9c3c", size = 4796669, upload-time = "2025-11-19T15:54:39.961Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/89/f0/8956f8a86b20d7bb9d6ac0187cf4cd54d8065bc9a1a09eb8011d4d326596/redis-7.1.0-py3-none-any.whl", hash = "sha256:23c52b208f92b56103e17c5d06bdc1a6c2c0b3106583985a76a18f83b265de2b", size = 354159, upload-time = "2025-11-19T15:54:38.064Z" }, +] + [[package]] name = "referencing" -version = "0.37.0" +version = "0.36.2" source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } wheels = [ - { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, ] [[package]] @@ -4303,6 +4931,19 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, ] +[[package]] +name = "rich-rst" +version = "1.3.2" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "docutils" }, + { name = "rich" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bc/6d/a506aaa4a9eaa945ed8ab2b7347859f53593864289853c5d6d62b77246e0/rich_rst-1.3.2.tar.gz", hash = "sha256:a1196fdddf1e364b02ec68a05e8ff8f6914fee10fbca2e6b6735f166bb0da8d4", size = 14936, upload-time = "2025-10-14T16:49:45.332Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/13/2f/b4530fbf948867702d0a3f27de4a6aab1d156f406d72852ab902c4d04de9/rich_rst-1.3.2-py3-none-any.whl", hash = "sha256:a99b4907cbe118cf9d18b0b44de272efa61f15117c61e39ebdc431baf5df722a", size = 12567, upload-time = "2025-10-14T16:49:42.953Z" }, +] + [[package]] name = "rpds-py" version = "0.30.0" @@ -4602,6 +5243,19 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/56/a5/df8f46ef7da168f1bc52cd86e09a9de5c6f19cc1da04454d51b7d4f43408/scipy-1.17.0-cp314-cp314t-win_arm64.whl", hash = "sha256:031121914e295d9791319a1875444d55079885bbae5bdc9c5e0f2ee5f09d34ff", size = 25246266, upload-time = "2026-01-10T21:30:45.923Z" }, ] +[[package]] +name = "secretstorage" +version = "3.5.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "cryptography" }, + { name = "jeepney" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" }, +] + [[package]] name = "shapely" version = "2.1.2" @@ -4706,6 +5360,15 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002, upload-time = "2021-11-16T18:38:34.792Z" }, ] +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + [[package]] name = "soupsieve" version = "2.8.3" @@ -4771,6 +5434,32 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882, upload-time = "2026-01-21T18:22:10.456Z" }, ] +[[package]] +name = "sse-starlette" +version = "3.2.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "anyio" }, + { name = "starlette" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" }, +] + +[[package]] +name = "starlette" +version = "0.52.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" }, +] + [[package]] name = "tenacity" version = "9.1.2" @@ -4972,6 +5661,21 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b0/be/69fffc97b78f52a5d1372e5d56a0599291e96996a47089fb6312bc023d88/trimesh-4.11.1-py3-none-any.whl", hash = "sha256:bcc082ced94610ecd2c09b031431d0f3ad74352525e23a41b5688a2897b3e3e0", size = 740352, upload-time = "2026-01-17T16:38:00.716Z" }, ] +[[package]] +name = "typer" +version = "0.21.1" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371, upload-time = "2026-01-06T11:21:10.989Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, +] + [[package]] name = "typer-slim" version = "0.21.1" @@ -5078,6 +5782,7 @@ dependencies = [ { name = "chardet" }, { name = "crawl4ai" }, { name = "croniter" }, + { name = "fastmcp" }, { name = "httpx" }, { name = "imgkit" }, { name = "langchain-community", version = "0.3.31", source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" }, marker = "python_full_version < '3.11'" }, @@ -5136,6 +5841,7 @@ requires-dist = [ { name = "chardet", specifier = ">=5.2.0" }, { name = "crawl4ai", specifier = ">=0.3.0" }, { name = "croniter", specifier = ">=2.0.0" }, + { name = "fastmcp", specifier = ">=2.14.4" }, { name = "httpx", specifier = ">=0.27.0" }, { name = "imgkit" }, { name = "langchain-community", specifier = ">=0.3.0" }, @@ -5218,6 +5924,20 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/63/d4/acad86ce012b42ce18a12f31ee2aa3cbeeb98664f865f05f68c882945913/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fd9112ca96978361201e669729784f26c71fecc9c13a7f8a07162c31bd4d1e2", size = 359217, upload-time = "2026-01-20T20:36:59.687Z" }, ] +[[package]] +name = "uvicorn" +version = "0.40.0" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +dependencies = [ + { name = "click" }, + { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, +] + [[package]] name = "websockets" version = "16.0" @@ -5286,6 +6006,75 @@ wheels = [ { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] +[[package]] +name = "wrapt" +version = "1.17.3" +source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" } +sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +wheels = [ + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3f/23/bb82321b86411eb51e5a5db3fb8f8032fd30bd7c2d74bfe936136b2fa1d6/wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04", size = 53482, upload-time = "2025-08-12T05:51:44.467Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/45/69/f3c47642b79485a30a59c63f6d739ed779fb4cc8323205d047d741d55220/wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2", size = 38676, upload-time = "2025-08-12T05:51:32.636Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d1/71/e7e7f5670c1eafd9e990438e69d8fb46fa91a50785332e06b560c869454f/wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c", size = 38957, upload-time = "2025-08-12T05:51:54.655Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/de/17/9f8f86755c191d6779d7ddead1a53c7a8aa18bccb7cea8e7e72dfa6a8a09/wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775", size = 81975, upload-time = "2025-08-12T05:52:30.109Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f2/15/dd576273491f9f43dd09fce517f6c2ce6eb4fe21681726068db0d0467096/wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd", size = 83149, upload-time = "2025-08-12T05:52:09.316Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0c/c4/5eb4ce0d4814521fee7aa806264bf7a114e748ad05110441cd5b8a5c744b/wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05", size = 82209, upload-time = "2025-08-12T05:52:10.331Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/31/4b/819e9e0eb5c8dc86f60dfc42aa4e2c0d6c3db8732bce93cc752e604bb5f5/wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418", size = 81551, upload-time = "2025-08-12T05:52:31.137Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f8/83/ed6baf89ba3a56694700139698cf703aac9f0f9eb03dab92f57551bd5385/wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390", size = 36464, upload-time = "2025-08-12T05:53:01.204Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2f/90/ee61d36862340ad7e9d15a02529df6b948676b9a5829fd5e16640156627d/wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6", size = 38748, upload-time = "2025-08-12T05:53:00.209Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bd/c3/cefe0bd330d389c9983ced15d326f45373f4073c9f4a8c2f99b50bfea329/wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18", size = 36810, upload-time = "2025-08-12T05:52:51.906Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, + { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, +] + [[package]] name = "xlsxwriter" version = "3.2.9" From 0916106710e38a26bb56414a95f3c28f498a6fdf Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:27:34 +0800 Subject: [PATCH 03/16] docs(readme): reorganize mcp configuration section Move MCP configuration documentation from the "Extension and Development" section to the "Configuration" section for better user experience. Changes: - Relocate MCP configuration guide to appear alongside other configuration instructions - Remove duplicate MCP support section from development section - Improve documentation structure by placing configuration information where users naturally look for it This change makes it easier for users to find MCP configuration instructions during the initial setup process. --- README.md | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index e8522261..c8009087 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,38 @@ uv run -m Undefined > 启动项目需要 OneBot 实例,推荐使用 [NapCat](https://napneko.github.io/)。 +### MCP 配置 + +Undefined 支持 MCP (Model Context Protocol) 协议,可以连接外部 MCP 服务器来扩展 AI 的工具能力。 + +#### 配置步骤 + +1. 复制 MCP 配置示例文件: + ```bash + cp config/mcp.json.example config/mcp.json + ``` + +2. 编辑 `config/mcp.json`,根据 MCP 服务器说明使用标准格式添加你需要的 MCP 服务器 + +3. 在 `.env` 中设置 MCP 配置文件路径(可选,默认为 `config/mcp.json`): + ```env + MCP_CONFIG_PATH=config/mcp.json + ``` + +#### 使用方式 + +配置完成后,AI 会自动加载 MCP 工具,工具名称格式为 `mcp.{server_name}.{tool_name}`。 + +例如,配置了 `filesystem` 服务器后,AI 可以使用 `mcp.filesystem.read_file` 等工具。 + +#### 可用的 MCP 服务器 + +> 需确保本地安装了 `nodejs` 以及 `npm` + +- [@upstash/context7-mcp](https://github.com/upstash/context7):Up-to-date Code Docs For Any Prompt + +> 更多服务器请自行添加 + ## 使用说明 ### 部署后的初始化 @@ -210,38 +242,6 @@ Undefined 采用模块化的 **Skills** 架构,扩展非常简单: 详细开发指南请参考 [src/Undefined/skills/README.md](src/Undefined/skills/README.md)。 -### MCP 支持 - -Undefined 支持 MCP (Model Context Protocol) 协议,可以连接外部 MCP 服务器来扩展 AI 的工具能力。 - -#### 配置 MCP - -1. 复制 MCP 配置示例文件: - ```bash - cp config/mcp.json.example config/mcp.json - ``` - -2. 编辑 `config/mcp.json` ,根据 MCP 服务器说明使用标准格式添加你需要的 MCP 服务器 - -3. 在 `.env` 中设置 MCP 配置文件路径(可选,默认为 `config/mcp.json`): - ```env - MCP_CONFIG_PATH=config/mcp.json - ``` - -#### 使用 MCP 工具 - -配置完成后,AI 会自动加载 MCP 工具,工具名称格式为 `mcp.{server_name}.{tool_name}`。 - -例如,配置了 `filesystem` 服务器后,AI 可以使用 `mcp.filesystem.read_file` 等工具。 - -#### 默认可用的 MCP 服务器 - -> 需确保本地安装了`nodejs`以及`npm` - -- [@upstash/context7-mcp](https://github.com/upstash/context7):Up-to-date Code Docs For Any Prompt - -> 更多服务器请自行添加 - ## 致谢与友链 ### NagaAgent From 8e8f814cad458d7f675f524443407ce55303f17a Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:29:50 +0800 Subject: [PATCH 04/16] docs(readme): add collapsible table of contents Add a collapsible table of contents at the beginning of README.md to improve navigation and user experience. Changes: - Add collapsible TOC using HTML
and tags - Include all main sections and subsections with anchor links - Style with bold title and clear hierarchy - Default to collapsed state to reduce visual clutter - Add separator lines above and below for better visual separation Benefits: - Easier navigation for long documentation - Quick access to specific sections - Improved readability without expanding content by default --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index c8009087..4e1e5032 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,33 @@ ### _与 [NagaAgent](https://github.com/Xxiii8322766509/NagaAgent) 进行联动!_ +--- + +
+目录 + +- [立即体验](#立即体验) +- [核心特性](#核心特性) +- [安装与部署](#安装与部署) + - [方式一:使用 pip 安装(推荐)](#方式一使用-pip-安装推荐) + - [方式二:源码部署(开发)](#方式二源码部署开发) + - [配置说明(通用)](#配置说明通用) + - [MCP 配置](#mcp-配置) +- [使用说明](#使用说明) + - [部署后的初始化](#部署后的初始化) + - [Agent 能力展示](#agent-能力展示) + - [管理员命令](#管理员命令) + - [消息优先级](#消息优先级) +- [目录结构](#目录结构) +- [扩展与开发](#扩展与开发) +- [致谢与友链](#致谢与友链) + - [NagaAgent](#nagaagent) +- [开源协议](#开源协议) + +
+ +--- + ## 立即体验 [点击添加官方实例QQ](https://qm.qq.com/q/cvjJoNysGA) From 605d2242bfcf0e0106d94202bd771918fc618549 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:34:30 +0800 Subject: [PATCH 05/16] fix(mcp): add config validation and improve error messages Add comprehensive validation for MCP server configuration format and provide clearer error messages to help users diagnose configuration issues. Changes: - Add type checking for server_config in _initialize_server method - Validate mcpServers array elements are dictionaries before processing - Provide detailed error messages explaining correct configuration format - Prevent crashes when config file contains invalid data types - Log configuration errors with specific index information This fix resolves AttributeError when mcpServers array contains strings instead of dictionary objects, which was causing the bot to crash during MCP initialization. --- src/Undefined/skills/toolsets/mcp/__init__.py | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py index ede7294a..3608718c 100644 --- a/src/Undefined/skills/toolsets/mcp/__init__.py +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -79,6 +79,17 @@ async def initialize(self) -> None: self._is_initialized = True return + # 验证配置格式 + invalid_configs = [i for i, s in enumerate(servers) if not isinstance(s, dict)] + if invalid_configs: + logger.error( + f"MCP 配置格式错误: mcpServers 数组中的索引 {invalid_configs} 不是有效的字典对象。" + f"请确保每个元素都是包含 name、command、args 字段的字典。" + ) + logger.info("MCP 工具集初始化已终止") + self._is_initialized = True + return + logger.info(f"开始初始化 {len(servers)} 个 MCP 服务器...") for server_config in servers: @@ -99,9 +110,20 @@ async def _initialize_server(self, server_config: Dict[str, Any]) -> None: 参数: server_config: 服务器配置,包含 name、command、args 等字段 """ + # 验证配置格式 + if not isinstance(server_config, dict): + logger.error( + f"MCP 服务器配置格式错误: 期望字典对象,实际收到 {type(server_config).__name__}。" + f"请检查 config/mcp.json 文件,mcpServers 数组中的每个元素应该是字典对象。" + ) + return + server_name = server_config.get("name") if not server_name: - logger.error("MCP 服务器配置缺少 name 字段") + logger.error( + "MCP 服务器配置缺少 name 字段。" + '正确的配置格式: {"name": "server_name", "command": "...", "args": [...]}' + ) return try: From cf46e3057757b6d3c4407c2a0aff7add14905457 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:41:49 +0800 Subject: [PATCH 06/16] fix(mcp): correct config format to match fastmcp standard Fix MCP configuration format to match FastMCP's expected format. FastMCP expects mcpServers as an object (dict) with server names as keys, not as an array. Changes: - Update initialize() to handle mcpServers as dict instead of array - Extract server_name from dict keys instead of name field - Update config/mcp.json.example with correct object format - Update all documentation examples in MCP README.md - Update error messages to reflect correct format Correct format: { "mcpServers": { "server_name": { "command": "npx", "args": ["-y", "@package/name"] } } } This fixes "No MCP servers defined in the config" error when using FastMCP Client with MCPConfigTransport. --- src/Undefined/skills/toolsets/mcp/README.md | 35 ++++++++----------- src/Undefined/skills/toolsets/mcp/__init__.py | 25 ++++++------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/Undefined/skills/toolsets/mcp/README.md b/src/Undefined/skills/toolsets/mcp/README.md index 24bffdec..563bff63 100644 --- a/src/Undefined/skills/toolsets/mcp/README.md +++ b/src/Undefined/skills/toolsets/mcp/README.md @@ -27,13 +27,12 @@ MCP 工具的命名格式为:`mcp.{server_name}.{tool_name}` ```json { - "mcpServers": [ - { - "name": "server_name", + "mcpServers": { + "server_name": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-name", "arg1", "arg2"] } - ] + } } ``` @@ -47,13 +46,12 @@ MCP 工具的命名格式为:`mcp.{server_name}.{tool_name}` ```json { - "mcpServers": [ - { - "name": "filesystem", + "mcpServers": { + "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/data"] } - ] + } } ``` @@ -66,13 +64,12 @@ AI 可以使用: ```json { - "mcpServers": [ - { - "name": "brave-search", + "mcpServers": { + "brave-search": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-brave-search"] } - ] + } } ``` @@ -83,13 +80,12 @@ AI 可以使用: ```json { - "mcpServers": [ - { - "name": "sqlite", + "mcpServers": { + "sqlite": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-sqlite", "--db-path", "/path/to/db.sqlite"] } - ] + } } ``` @@ -100,13 +96,12 @@ AI 可以使用: ```json { - "mcpServers": [ - { - "name": "github", + "mcpServers": { + "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] } - ] + } } ``` diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py index 3608718c..976f81f8 100644 --- a/src/Undefined/skills/toolsets/mcp/__init__.py +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -72,27 +72,28 @@ async def initialize(self) -> None: self._server_tools = {} config = self.load_mcp_config() - servers = config.get("mcpServers", []) + mcp_servers = config.get("mcpServers", {}) - if not servers: + if not mcp_servers: logger.info("未配置 MCP 服务器") self._is_initialized = True return - # 验证配置格式 - invalid_configs = [i for i, s in enumerate(servers) if not isinstance(s, dict)] - if invalid_configs: + # FastMCP 配置格式: mcpServers 是一个对象,键为服务器名称,值为配置 + if not isinstance(mcp_servers, dict): logger.error( - f"MCP 配置格式错误: mcpServers 数组中的索引 {invalid_configs} 不是有效的字典对象。" - f"请确保每个元素都是包含 name、command、args 字段的字典。" + f"MCP 配置格式错误: mcpServers 应该是一个对象(字典),实际类型为 {type(mcp_servers).__name__}。" + '正确的格式: {"mcpServers": {"server_name": {"command": "...", "args": [...]}}}' ) - logger.info("MCP 工具集初始化已终止") self._is_initialized = True return - logger.info(f"开始初始化 {len(servers)} 个 MCP 服务器...") + logger.info(f"开始初始化 {len(mcp_servers)} 个 MCP 服务器...") - for server_config in servers: + for server_name, server_config in mcp_servers.items(): + # 将服务器名称添加到配置中 + if isinstance(server_config, dict): + server_config["name"] = server_name await self._initialize_server(server_config) total_tools = len(self._tools_handlers) @@ -114,7 +115,7 @@ async def _initialize_server(self, server_config: Dict[str, Any]) -> None: if not isinstance(server_config, dict): logger.error( f"MCP 服务器配置格式错误: 期望字典对象,实际收到 {type(server_config).__name__}。" - f"请检查 config/mcp.json 文件,mcpServers 数组中的每个元素应该是字典对象。" + f"请检查 config/mcp.json 文件,mcpServers 对象的值应该是字典对象。" ) return @@ -122,7 +123,7 @@ async def _initialize_server(self, server_config: Dict[str, Any]) -> None: if not server_name: logger.error( "MCP 服务器配置缺少 name 字段。" - '正确的配置格式: {"name": "server_name", "command": "...", "args": [...]}' + '正确的配置格式: {"mcpServers": {"server_name": {"command": "...", "args": [...]}}}' ) return From 9c44cf0031a140bb570044eeebec93afb697d63d Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:48:53 +0800 Subject: [PATCH 07/16] refactor(mcp): use single client with config dict Refactor MCP registry to use a single FastMCP Client with the full configuration dictionary instead of creating separate clients for each server. This matches FastMCP's recommended usage pattern. Changes: - Remove per-server client management (_mcp_clients, _server_tools) - Use Client(config) with full mcpServers configuration - Tools are automatically prefixed by FastMCP - Simplify tool registration and execution logic - Remove _initialize_server method (no longer needed) Benefits: - Matches FastMCP's documented usage pattern - Simpler code with fewer moving parts - Better resource management (single client connection) - Automatic tool prefixing by FastMCP --- src/Undefined/skills/toolsets/mcp/__init__.py | 116 +++++------------- 1 file changed, 33 insertions(+), 83 deletions(-) diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py index 976f81f8..d2e4d10b 100644 --- a/src/Undefined/skills/toolsets/mcp/__init__.py +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -35,8 +35,7 @@ def __init__(self, config_path: str | Path | None = None) -> None: self._tools_handlers: Dict[ str, Callable[[Dict[str, Any], Dict[str, Any]], Awaitable[str]] ] = {} - self._mcp_clients: Dict[str, Any] = {} # server_name -> client - self._server_tools: Dict[str, List[str]] = {} # server_name -> tool_names + self._mcp_client: Any = None self._is_initialized: bool = False def load_mcp_config(self) -> Dict[str, Any]: @@ -47,7 +46,7 @@ def load_mcp_config(self) -> Dict[str, Any]: """ if not self.config_path.exists(): logger.warning(f"MCP 配置文件不存在: {self.config_path}") - return {"mcpServers": []} + return {"mcpServers": {}} try: with open(self.config_path, "r", encoding="utf-8") as f: @@ -56,10 +55,10 @@ def load_mcp_config(self) -> Dict[str, Any]: return cast(Dict[str, Any], config) except json.JSONDecodeError as e: logger.error(f"MCP 配置文件格式错误: {e}") - return {"mcpServers": []} + return {"mcpServers": {}} except Exception as e: logger.error(f"加载 MCP 配置失败: {e}") - return {"mcpServers": []} + return {"mcpServers": {}} async def initialize(self) -> None: """初始化 MCP 工具集 @@ -68,8 +67,6 @@ async def initialize(self) -> None: """ self._tools_schema = [] self._tools_handlers = {} - self._mcp_clients = {} - self._server_tools = {} config = self.load_mcp_config() mcp_servers = config.get("mcpServers", {}) @@ -90,88 +87,41 @@ async def initialize(self) -> None: logger.info(f"开始初始化 {len(mcp_servers)} 个 MCP 服务器...") - for server_name, server_config in mcp_servers.items(): - # 将服务器名称添加到配置中 - if isinstance(server_config, dict): - server_config["name"] = server_name - await self._initialize_server(server_config) - - total_tools = len(self._tools_handlers) - logger.info(f"MCP 工具集初始化完成,共加载 {total_tools} 个工具") - - # 输出详细统计 - for server_name, tools in self._server_tools.items(): - logger.info(f" - [{server_name}] ({len(tools)} 个): {', '.join(tools)}") - - self._is_initialized = True - - async def _initialize_server(self, server_config: Dict[str, Any]) -> None: - """初始化单个 MCP 服务器 - - 参数: - server_config: 服务器配置,包含 name、command、args 等字段 - """ - # 验证配置格式 - if not isinstance(server_config, dict): - logger.error( - f"MCP 服务器配置格式错误: 期望字典对象,实际收到 {type(server_config).__name__}。" - f"请检查 config/mcp.json 文件,mcpServers 对象的值应该是字典对象。" - ) - return - - server_name = server_config.get("name") - if not server_name: - logger.error( - "MCP 服务器配置缺少 name 字段。" - '正确的配置格式: {"mcpServers": {"server_name": {"command": "...", "args": [...]}}}' - ) - return - try: # 延迟导入 fastmcp from fastmcp import Client - # 创建客户端 - client = Client(server_config) + # 创建客户端,传入完整配置 + self._mcp_client = Client(config) # 连接并初始化 - async with client: - if not client.is_connected(): - logger.warning(f"无法连接到 MCP 服务器: {server_name}") + async with self._mcp_client: + if not self._mcp_client.is_connected(): + logger.warning("无法连接到 MCP 服务器") + self._is_initialized = True return - # 获取工具列表 - tools = await client.list_tools() - - # 保存客户端引用(用于后续调用) - self._mcp_clients[server_name] = client - self._server_tools[server_name] = [] + # 获取所有工具列表 + tools = await self._mcp_client.list_tools() # 转换每个工具为 toolsets 格式 for tool in tools: - await self._register_tool(server_name, tool, client) + await self._register_tool(tool) - logger.info( - f"MCP 服务器 [{server_name}] 初始化成功,加载 {len(tools)} 个工具" - ) + logger.info(f"MCP 工具集初始化完成,共加载 {len(tools)} 个工具") except ImportError: logger.error("fastmcp 库未安装,MCP 功能将不可用") except Exception as e: - logger.exception(f"初始化 MCP 服务器 [{server_name}] 失败: {e}") + logger.exception(f"初始化 MCP 工具集失败: {e}") - async def _register_tool( - self, - server_name: str, - tool: Any, - client: Any, - ) -> None: + self._is_initialized = True + + async def _register_tool(self, tool: Any) -> None: """注册单个 MCP 工具 参数: - server_name: 服务器名称 tool: MCP 工具对象 - client: MCP 客户端实例 """ try: # 获取工具信息 @@ -181,15 +131,16 @@ async def _register_tool( # 构建工具参数 schema parameters = tool.inputSchema if hasattr(tool, "inputSchema") else {} - # 构建完整的工具名称:mcp.{server_name}.{tool_name} - full_tool_name = f"mcp.{server_name}.{tool_name}" + # FastMCP 会自动为工具添加服务器名称前缀,格式为 {server_name}_{tool_name} + # 但我们需要转换为 mcp.{server_name}.{tool_name} 格式 + full_tool_name = f"mcp.{tool_name}" # 构建 OpenAI function calling 格式的 schema schema = { "type": "function", "function": { "name": full_tool_name, - "description": f"[MCP:{server_name}] {tool_description}", + "description": f"[MCP] {tool_description}", "parameters": parameters, }, } @@ -198,8 +149,8 @@ async def _register_tool( async def handler(args: Dict[str, Any], context: Dict[str, Any]) -> str: """MCP 工具处理器""" try: - # 调用 MCP 工具 - result = await client.call_tool(tool_name, args) + # 调用 MCP 工具(使用原始工具名,不包含 mcp 前缀) + result = await self._mcp_client.call_tool(tool_name, args) # 解析结果 if hasattr(result, "content") and result.content: @@ -219,12 +170,11 @@ async def handler(args: Dict[str, Any], context: Dict[str, Any]) -> str: # 注册工具 self._tools_schema.append(schema) self._tools_handlers[full_tool_name] = handler - self._server_tools[server_name].append(tool_name) logger.debug(f"已注册 MCP 工具: {full_tool_name}") except Exception as e: - logger.error(f"注册 MCP 工具失败 [{server_name}/{tool.name}]: {e}") + logger.error(f"注册 MCP 工具失败 [{tool.name}]: {e}") def get_tools_schema(self) -> List[Dict[str, Any]]: """获取所有 MCP 工具的 Schema""" @@ -239,7 +189,7 @@ async def execute_tool( """执行指定的 MCP 工具 参数: - tool_name: 工具名称(格式:mcp.{server_name}.{tool_name}) + tool_name: 工具名称(格式:mcp.{server_name}_{tool_name}) args: 工具参数 context: 执行上下文 @@ -261,16 +211,16 @@ async def execute_tool( return f"执行 MCP 工具 {tool_name} 时出错: {str(e)}" async def close(self) -> None: - """关闭所有 MCP 客户端连接""" + """关闭 MCP 客户端连接""" logger.info("正在关闭 MCP 客户端连接...") - for server_name, client in self._mcp_clients.items(): + if self._mcp_client: try: - # fastmcp.Client 使用 context manager,连接会自动关闭 - logger.debug(f"已关闭 MCP 服务器 [{server_name}] 连接") + # FastMCP Client 使用 context manager,连接会自动关闭 + logger.debug("已关闭 MCP 客户端连接") except Exception as e: - logger.warning(f"关闭 MCP 服务器 [{server_name}] 连接时出错: {e}") - self._mcp_clients.clear() - logger.info("MCP 客户端连接已全部关闭") + logger.warning(f"关闭 MCP 客户端连接时出错: {e}") + self._mcp_client = None + logger.info("MCP 客户端连接已关闭") @property def is_initialized(self) -> bool: From 979699b5e9453d14889cc4283c240fb5369134cb Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:52:16 +0800 Subject: [PATCH 08/16] fix(mcp): change tool name format from underscore to dot separator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change MCP tool name format to use dot separator instead of underscore. FastMCP auto-prefixes tools with server_name_tool_name format, but we want mcp.server_name.tool_name format. Changes: - Replace first underscore in tool_name with dot - Example: context7_resolve-library-id → mcp.context7.resolve-library-id - Update execute_tool docstring to reflect new format This provides cleaner, more consistent tool naming that matches the toolset naming convention used elsewhere in the project. --- src/Undefined/skills/toolsets/mcp/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py index d2e4d10b..6fd12ca9 100644 --- a/src/Undefined/skills/toolsets/mcp/__init__.py +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -132,8 +132,9 @@ async def _register_tool(self, tool: Any) -> None: parameters = tool.inputSchema if hasattr(tool, "inputSchema") else {} # FastMCP 会自动为工具添加服务器名称前缀,格式为 {server_name}_{tool_name} - # 但我们需要转换为 mcp.{server_name}.{tool_name} 格式 - full_tool_name = f"mcp.{tool_name}" + # 我们需要转换为 mcp.{server_name}.{tool_name} 格式(用点代替下划线) + # 例如: context7_resolve-library-id → mcp.context7.resolve-library-id + full_tool_name = f"mcp.{tool_name.replace('_', '.', 1)}" # 构建 OpenAI function calling 格式的 schema schema = { From a93b25069671cdf16672a31119dccc92548ae542 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 14:55:02 +0800 Subject: [PATCH 09/16] fix(mcp): correctly parse server prefix from tool names Fix tool name parsing to correctly extract server name and tool name from FastMCP's server_name_tool_name format. Changes: - Store mcp_servers config for prefix matching - Parse tool names to extract server_name and tool_name - Use correct format for schema (mcp.server_name.tool_name) - Use correct format for FastMCP calls (server_name_tool_name) - Fix indentation error in __init__ method Example: - FastMCP tool name: context7_resolve-library-id - Schema name: mcp.context7.resolve-library-id - Call name: context7_resolve-library-id --- src/Undefined/skills/toolsets/mcp/__init__.py | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py index 6fd12ca9..8b0ce01a 100644 --- a/src/Undefined/skills/toolsets/mcp/__init__.py +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -36,6 +36,7 @@ def __init__(self, config_path: str | Path | None = None) -> None: str, Callable[[Dict[str, Any], Dict[str, Any]], Awaitable[str]] ] = {} self._mcp_client: Any = None + self._mcp_servers: Dict[str, Any] = {} # 保存服务器配置 self._is_initialized: bool = False def load_mcp_config(self) -> Dict[str, Any]: @@ -87,6 +88,9 @@ async def initialize(self) -> None: logger.info(f"开始初始化 {len(mcp_servers)} 个 MCP 服务器...") + # 保存服务器配置 + self._mcp_servers = mcp_servers + try: # 延迟导入 fastmcp from fastmcp import Client @@ -131,10 +135,26 @@ async def _register_tool(self, tool: Any) -> None: # 构建工具参数 schema parameters = tool.inputSchema if hasattr(tool, "inputSchema") else {} - # FastMCP 会自动为工具添加服务器名称前缀,格式为 {server_name}_{tool_name} - # 我们需要转换为 mcp.{server_name}.{tool_name} 格式(用点代替下划线) - # 例如: context7_resolve-library-id → mcp.context7.resolve-library-id - full_tool_name = f"mcp.{tool_name.replace('_', '.', 1)}" + # FastMCP 使用 server_name_tool_name 格式调用工具 + # 我们需要转换为 mcp.server_name.tool_name 格式 + # 遍历服务器配置,找到匹配的服务器名称 + server_name = None + for name in self._mcp_servers.keys(): + # 检查工具名是否以服务器名开头 + if tool_name.startswith(f"{name}_"): + server_name = name + # 提取实际的工具名(去掉服务器前缀) + tool_name = tool_name[len(name) + 1 :] + break + + if server_name: + full_tool_name = f"mcp.{server_name}.{tool_name}" + # 调用 FastMCP 时需要使用原始的 server_name_tool_name 格式 + original_tool_name = f"{server_name}_{tool_name}" + else: + # 如果没有找到服务器前缀,直接使用 mcp. 前缀 + full_tool_name = f"mcp.{tool_name}" + original_tool_name = tool_name # 构建 OpenAI function calling 格式的 schema schema = { @@ -150,8 +170,8 @@ async def _register_tool(self, tool: Any) -> None: async def handler(args: Dict[str, Any], context: Dict[str, Any]) -> str: """MCP 工具处理器""" try: - # 调用 MCP 工具(使用原始工具名,不包含 mcp 前缀) - result = await self._mcp_client.call_tool(tool_name, args) + # 调用 MCP 工具(使用 FastMCP 期望的格式:server_name_tool_name) + result = await self._mcp_client.call_tool(original_tool_name, args) # 解析结果 if hasattr(result, "content") and result.content: From 40605a95dee719ea8195395ff25e1cefd9b67de9 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 15:03:22 +0800 Subject: [PATCH 10/16] fix(mcp): handle single vs multi-server tool naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix tool naming to correctly handle FastMCP's behavior where: - Single server: tool names don't have prefix (e.g., resolve-library-id) - Multi server: tool names have prefix (e.g., context7_resolve-library-id) Changes: - Check if tool name contains server prefix - For single server without prefix, use that server name - For multi server with prefix, extract server and tool names - Always use mcp.server_name.tool_name format for schema - Use original tool name (with or without prefix) for FastMCP calls Example: - Single server: resolve-library-id → mcp.context7.resolve-library-id - Multi server: context7_resolve-library-id → mcp.context7.resolve-library-id This fix was discovered through local testing with uv. --- src/Undefined/skills/toolsets/mcp/__init__.py | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py index 8b0ce01a..d9d70269 100644 --- a/src/Undefined/skills/toolsets/mcp/__init__.py +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -135,27 +135,38 @@ async def _register_tool(self, tool: Any) -> None: # 构建工具参数 schema parameters = tool.inputSchema if hasattr(tool, "inputSchema") else {} - # FastMCP 使用 server_name_tool_name 格式调用工具 - # 我们需要转换为 mcp.server_name.tool_name 格式 - # 遍历服务器配置,找到匹配的服务器名称 + # FastMCP 的行为: + # - 单服务器:工具名不带前缀(如 resolve-library-id) + # - 多服务器:工具名带服务器前缀(如 context7_resolve-library-id) server_name = None + actual_tool_name = tool_name + + # 检查工具名是否包含服务器前缀 for name in self._mcp_servers.keys(): - # 检查工具名是否以服务器名开头 if tool_name.startswith(f"{name}_"): server_name = name # 提取实际的工具名(去掉服务器前缀) - tool_name = tool_name[len(name) + 1 :] + actual_tool_name = tool_name[len(name) + 1 :] break - if server_name: - full_tool_name = f"mcp.{server_name}.{tool_name}" - # 调用 FastMCP 时需要使用原始的 server_name_tool_name 格式 - original_tool_name = f"{server_name}_{tool_name}" + # 如果只有一个服务器且工具名没有前缀,使用该服务器名 + if server_name is None and len(self._mcp_servers) == 1: + server_name = list(self._mcp_servers.keys())[0] + # FastMCP 调用时使用原始工具名(不带前缀) + original_tool_name = tool_name + elif server_name: + # 多服务器,工具名已包含前缀 + original_tool_name = tool_name else: - # 如果没有找到服务器前缀,直接使用 mcp. 前缀 - full_tool_name = f"mcp.{tool_name}" + # 无法确定服务器,直接使用原始工具名 original_tool_name = tool_name + # 构建完整的工具名称:mcp.{server_name}.{tool_name} + if server_name: + full_tool_name = f"mcp.{server_name}.{actual_tool_name}" + else: + full_tool_name = f"mcp.{actual_tool_name}" + # 构建 OpenAI function calling 格式的 schema schema = { "type": "function", @@ -170,7 +181,7 @@ async def _register_tool(self, tool: Any) -> None: async def handler(args: Dict[str, Any], context: Dict[str, Any]) -> str: """MCP 工具处理器""" try: - # 调用 MCP 工具(使用 FastMCP 期望的格式:server_name_tool_name) + # 调用 MCP 工具(使用 FastMCP 期望的工具名) result = await self._mcp_client.call_tool(original_tool_name, args) # 解析结果 @@ -192,7 +203,9 @@ async def handler(args: Dict[str, Any], context: Dict[str, Any]) -> str: self._tools_schema.append(schema) self._tools_handlers[full_tool_name] = handler - logger.debug(f"已注册 MCP 工具: {full_tool_name}") + logger.debug( + f"已注册 MCP 工具: {full_tool_name} (原始: {original_tool_name})" + ) except Exception as e: logger.error(f"注册 MCP 工具失败 [{tool.name}]: {e}") From 96bddf547aae3961d01e4e8759f243d862744c56 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 15:06:53 +0800 Subject: [PATCH 11/16] feat(tools): show tool summary after MCP initialization Move tool summary display to show after MCP tools are loaded. Changes: - Extract tool summary logic into _log_tools_summary() method - Show initial summary without MCP tools during load_tools() - Show complete summary with MCP tools after initialize_mcp_toolsets() - Add 'MCP tools: (waiting for async initialization...)' status in initial summary Benefits: - Users see complete tool count including MCP tools after initialization - Clear indication that MCP tools are loading asynchronously - Better visibility of when MCP tools become available --- src/Undefined/skills/tools/__init__.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Undefined/skills/tools/__init__.py b/src/Undefined/skills/tools/__init__.py index 489c33f8..e2237701 100644 --- a/src/Undefined/skills/tools/__init__.py +++ b/src/Undefined/skills/tools/__init__.py @@ -39,7 +39,15 @@ def load_tools(self) -> None: # 3. 加载 MCP 工具集(创建注册表,但不初始化) self._load_mcp_toolsets() - # 4. 输出详细的工具列表 + # 4. 输出工具列表(不包含 MCP 工具,因为 MCP 还未初始化) + self._log_tools_summary(include_mcp=False) + + def _log_tools_summary(self, include_mcp: bool = True) -> None: + """输出工具加载统计 + + 参数: + include_mcp: 是否包含 MCP 工具 + """ tool_names = list(self._items_handlers.keys()) basic_tools = [name for name in tool_names if "." not in name] toolset_tools = [ @@ -56,7 +64,10 @@ def load_tools(self) -> None: toolset_by_category[category].append(name) logger.info("=" * 60) - logger.info("工具加载完成统计") + if include_mcp: + logger.info("工具加载完成统计") + else: + logger.info("工具加载完成统计(MCP 工具待初始化)") logger.info( f" - 基础工具 ({len(basic_tools)} 个): {', '.join(basic_tools) if basic_tools else '无'}" ) @@ -64,8 +75,10 @@ def load_tools(self) -> None: logger.info(f" - 工具集工具 ({len(toolset_tools)} 个):") for category, tools in sorted(toolset_by_category.items()): logger.info(f" [{category}] ({len(tools)} 个): {', '.join(tools)}") - if mcp_tools: + if mcp_tools and include_mcp: logger.info(f" - MCP 工具 ({len(mcp_tools)} 个): {', '.join(mcp_tools)}") + elif not include_mcp and hasattr(self, "_mcp_registry") and self._mcp_registry: + logger.info(" - MCP 工具: (等待异步初始化...)") logger.info(f" - 总计: {len(tool_names)} 个工具") logger.info("=" * 60) @@ -127,6 +140,9 @@ async def initialize_mcp_toolsets(self) -> None: f"MCP 工具集已集成到主注册表,共 {len(self._mcp_registry._tools_handlers)} 个工具" ) + # 输出包含 MCP 工具的完整统计 + self._log_tools_summary(include_mcp=True) + except Exception as e: logger.exception(f"初始化 MCP 工具集失败: {e}") From 93dfb9b49e70486c0191d121f2d9903ed6418a28 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 15:11:54 +0800 Subject: [PATCH 12/16] feat(config): add howtocook-mcp server configuration example Add example configuration for howtocook-mcp server to MCP config file. Also standardize indentation from 2 to 4 spaces and ensure proper trailing newline. --- config/mcp.json.example | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/config/mcp.json.example b/config/mcp.json.example index 553d5d48..a8de3559 100644 --- a/config/mcp.json.example +++ b/config/mcp.json.example @@ -1,8 +1,12 @@ { - "mcpServers": { - "context7": { - "command": "npx", - "args": ["-y", "@upstash/context7-mcp"] + "mcpServers": { + "context7": { + "command": "npx", + "args": ["-y", "@upstash/context7-mcp"] + }, + "howtocook-mcp": { + "command": "npx", + "args": ["-y", "howtocook-mcp"] + } } - } -} \ No newline at end of file +} From 3b426935d703734069af7ed9f462c0cea5035018 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 15:19:41 +0800 Subject: [PATCH 13/16] docs(mcp): add howtocook-mcp example to MCP README Add howtocook-mcp server configuration example to MCP toolset README documentation. Changes: - Add howtocook-mcp usage example - Update available servers list with more categories This helps users discover and configure more MCP servers. --- README.md | 45 +++++++++++++++++++-- src/Undefined/skills/toolsets/mcp/README.md | 34 ++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4e1e5032..7a583dfb 100644 --- a/README.md +++ b/README.md @@ -188,9 +188,48 @@ Undefined 支持 MCP (Model Context Protocol) 协议,可以连接外部 MCP > 需确保本地安装了 `nodejs` 以及 `npm` -- [@upstash/context7-mcp](https://github.com/upstash/context7):Up-to-date Code Docs For Any Prompt - -> 更多服务器请自行添加 +以下是常用的 MCP 服务器示例: + +**文档与知识库** +- [@upstash/context7-mcp](https://github.com/upstash/context7):获取最新的代码库文档和示例 +- [howtocook-mcp](https://github.com/ModelCloud/howtocook-mcp):烹饪食谱查询 + +**文件系统与数据库** +- [@modelcontextprotocol/server-filesystem](https://github.com/modelcontextprotocol/servers):文件系统访问 +- [@modelcontextprotocol/server-sqlite](https://github.com/modelcontextprotocol/servers):SQLite 数据库操作 +- [@modelcontextprotocol/server-postgres](https://github.com/modelcontextprotocol/servers):PostgreSQL 数据库操作 + +**搜索与网络** +- [@modelcontextprotocol/server-brave-search](https://github.com/modelcontextprotocol/servers):Brave 搜索引擎 +- [@modelcontextprotocol/server-puppeteer](https://github.com/modelcontextprotocol/servers):网页抓取与自动化 + +**代码与开发** +- [@modelcontextprotocol/server-github](https://github.com/modelcontextprotocol/servers):GitHub API 集成 +- [@modelcontextprotocol/server-git](https://github.com/modelcontextprotocol/servers):Git 仓库操作 + +**更多服务器** +- 访问 [MCP Servers 仓库](https://github.com/modelcontextprotocol/servers) 查看完整列表 + +#### 配置示例 + +```json +{ + "mcpServers": { + "context7": { + "command": "npx", + "args": ["-y", "@upstash/context7-mcp"] + }, + "howtocook": { + "command": "npx", + "args": ["-y", "howtocook-mcp"] + }, + "filesystem": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"] + } + } +} +``` ## 使用说明 diff --git a/src/Undefined/skills/toolsets/mcp/README.md b/src/Undefined/skills/toolsets/mcp/README.md index 563bff63..1c77ee0d 100644 --- a/src/Undefined/skills/toolsets/mcp/README.md +++ b/src/Undefined/skills/toolsets/mcp/README.md @@ -109,6 +109,40 @@ AI 可以使用: - `mcp.github.get_repository`:获取仓库信息 - `mcp.github.list_issues`:列出 Issues +### 5. 代码文档查询 (Context7) + +```json +{ + "mcpServers": { + "context7": { + "command": "npx", + "args": ["-y", "@upstash/context7-mcp"] + } + } +} +``` + +AI 可以使用: +- `mcp.context7.resolve-library-id`:解析库名称获取库 ID +- `mcp.context7.query-docs`:查询库的文档和代码示例 + +### 6. 烹饪食谱查询 (HowToCook) + +```json +{ + "mcpServers": { + "howtocook": { + "command": "npx", + "args": ["-y", "howtocook-mcp"] + } + } +} +``` + +AI 可以使用: +- `mcp.howtocook.get_recipe`:获取烹饪食谱 +- `mcp.howtocook.search_ingredients`:搜索食材 + ## 注意事项 1. **依赖安装**:使用 MCP 功能需要安装 `fastmcp` 库 From 2e3bd06c2d122b6651b4bec8d94629948fa844d1 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 15:28:29 +0800 Subject: [PATCH 14/16] docs(mcp): restructure and simplify MCP documentation Reorganize MCP documentation to improve readability and reduce redundancy. Changes: - Consolidate available MCP servers section into "Built-in Available MCP Servers" - Simplify server list to show only context7 and howtocook examples - Add recommendation to visit mcp.so for discovering more servers - Move configuration format section before examples for better flow - Collapse configuration examples into
tag to reduce visual clutter - Remove redundant tool usage descriptions from mcp/README.md - Add trailing period to warning note for consistency Benefits: - Cleaner, more focused documentation - Easier for users to find essential information - Reduced redundancy between main README and toolset README - Better visual hierarchy with collapsible sections --- README.md | 46 +++++++++------------ src/Undefined/skills/toolsets/mcp/README.md | 8 ---- 2 files changed, 19 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 7a583dfb..ee78978f 100644 --- a/README.md +++ b/README.md @@ -184,45 +184,36 @@ Undefined 支持 MCP (Model Context Protocol) 协议,可以连接外部 MCP 例如,配置了 `filesystem` 服务器后,AI 可以使用 `mcp.filesystem.read_file` 等工具。 -#### 可用的 MCP 服务器 +#### 内置可用的 MCP 服务器 -> 需确保本地安装了 `nodejs` 以及 `npm` +> 需确保本地安装了 `nodejs` 以及 `npm`。 +> 更多服务器请自行配置。 +> 推荐:可前往 [mcp.so - Find Awesome MCP Servers and Clients](https://mcp.so) 检索感兴趣的 mcp。 -以下是常用的 MCP 服务器示例: - -**文档与知识库** - [@upstash/context7-mcp](https://github.com/upstash/context7):获取最新的代码库文档和示例 - [howtocook-mcp](https://github.com/ModelCloud/howtocook-mcp):烹饪食谱查询 -**文件系统与数据库** -- [@modelcontextprotocol/server-filesystem](https://github.com/modelcontextprotocol/servers):文件系统访问 -- [@modelcontextprotocol/server-sqlite](https://github.com/modelcontextprotocol/servers):SQLite 数据库操作 -- [@modelcontextprotocol/server-postgres](https://github.com/modelcontextprotocol/servers):PostgreSQL 数据库操作 - -**搜索与网络** -- [@modelcontextprotocol/server-brave-search](https://github.com/modelcontextprotocol/servers):Brave 搜索引擎 -- [@modelcontextprotocol/server-puppeteer](https://github.com/modelcontextprotocol/servers):网页抓取与自动化 +#### 配置格式 -**代码与开发** -- [@modelcontextprotocol/server-github](https://github.com/modelcontextprotocol/servers):GitHub API 集成 -- [@modelcontextprotocol/server-git](https://github.com/modelcontextprotocol/servers):Git 仓库操作 +```json +{ + "mcpServers": { + "filesystem": { + "command": "cmd" + "args": ["arg1", "arg2"] + } + } +} +``` -**更多服务器** -- 访问 [MCP Servers 仓库](https://github.com/modelcontextprotocol/servers) 查看完整列表 +如需添加多个,仅需在`mcpServers`键下添加子键。 -#### 配置示例 +
+配置示例 ```json { "mcpServers": { - "context7": { - "command": "npx", - "args": ["-y", "@upstash/context7-mcp"] - }, - "howtocook": { - "command": "npx", - "args": ["-y", "howtocook-mcp"] - }, "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"] @@ -230,6 +221,7 @@ Undefined 支持 MCP (Model Context Protocol) 协议,可以连接外部 MCP } } ``` +
## 使用说明 diff --git a/src/Undefined/skills/toolsets/mcp/README.md b/src/Undefined/skills/toolsets/mcp/README.md index 1c77ee0d..5cbcc738 100644 --- a/src/Undefined/skills/toolsets/mcp/README.md +++ b/src/Undefined/skills/toolsets/mcp/README.md @@ -105,10 +105,6 @@ AI 可以使用: } ``` -AI 可以使用: -- `mcp.github.get_repository`:获取仓库信息 -- `mcp.github.list_issues`:列出 Issues - ### 5. 代码文档查询 (Context7) ```json @@ -122,10 +118,6 @@ AI 可以使用: } ``` -AI 可以使用: -- `mcp.context7.resolve-library-id`:解析库名称获取库 ID -- `mcp.context7.query-docs`:查询库的文档和代码示例 - ### 6. 烹饪食谱查询 (HowToCook) ```json From 58e37c4e897981f9595af0abce5f4d99616083eb Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 15:32:17 +0800 Subject: [PATCH 15/16] refactor(tools): move tool summary logging inside MCP tools check Restructure the tool loading summary output to only display when MCP tools are present and included. This prevents unnecessary logging when MCP tools are not available. Changes: - Move entire logging block inside 'if mcp_tools and include_mcp:' condition - Comment out redundant conditional checks for MCP tools display - Ensure summary only appears when MCP tools are actually loaded Benefits: - Cleaner log output when MCP tools are not configured - Eliminates redundant conditional logic - More precise control over when tool statistics are displayed --- src/Undefined/skills/tools/__init__.py | 35 ++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Undefined/skills/tools/__init__.py b/src/Undefined/skills/tools/__init__.py index e2237701..32f5b7f0 100644 --- a/src/Undefined/skills/tools/__init__.py +++ b/src/Undefined/skills/tools/__init__.py @@ -63,24 +63,27 @@ def _log_tools_summary(self, include_mcp: bool = True) -> None: toolset_by_category[category] = [] toolset_by_category[category].append(name) - logger.info("=" * 60) - if include_mcp: - logger.info("工具加载完成统计") - else: - logger.info("工具加载完成统计(MCP 工具待初始化)") - logger.info( - f" - 基础工具 ({len(basic_tools)} 个): {', '.join(basic_tools) if basic_tools else '无'}" - ) - if toolset_by_category: - logger.info(f" - 工具集工具 ({len(toolset_tools)} 个):") - for category, tools in sorted(toolset_by_category.items()): - logger.info(f" [{category}] ({len(tools)} 个): {', '.join(tools)}") if mcp_tools and include_mcp: + logger.info("=" * 60) + if include_mcp: + logger.info("工具加载完成统计") + else: + logger.info("工具加载完成统计(MCP 工具待初始化)") + logger.info( + f" - 基础工具 ({len(basic_tools)} 个): {', '.join(basic_tools) if basic_tools else '无'}" + ) + if toolset_by_category: + logger.info(f" - 工具集工具 ({len(toolset_tools)} 个):") + for category, tools in sorted(toolset_by_category.items()): + logger.info( + f" [{category}] ({len(tools)} 个): {', '.join(tools)}" + ) + # if mcp_tools and include_mcp: logger.info(f" - MCP 工具 ({len(mcp_tools)} 个): {', '.join(mcp_tools)}") - elif not include_mcp and hasattr(self, "_mcp_registry") and self._mcp_registry: - logger.info(" - MCP 工具: (等待异步初始化...)") - logger.info(f" - 总计: {len(tool_names)} 个工具") - logger.info("=" * 60) + # elif not include_mcp and hasattr(self, "_mcp_registry") and self._mcp_registry: + # logger.info(" - MCP 工具: (等待异步初始化...)") + logger.info(f" - 总计: {len(tool_names)} 个工具") + logger.info("=" * 60) def _load_toolsets_recursive(self) -> None: """从 toolsets 目录发现并加载工具集。 From 65012607e6d0bdb7e6c04d0bb8e48015c30bfe26 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 24 Jan 2026 15:36:05 +0800 Subject: [PATCH 16/16] fix(mcp): maintain persistent connection for tool execution Fix RuntimeError when calling MCP tools after initialization. The client connection was being closed immediately after the context manager block ended, causing subsequent tool calls to fail with 'Client is not connected' error. Changes: - Replace async with context manager with manual __aenter__() call in initialize() - Manually call __aexit__() in close() method to properly close connection - Keep client connection active throughout the application lifecycle Benefits: - MCP tools can be called successfully after initialization - Connection persists until explicit close() is called - Fixes tool execution failures in production environment --- src/Undefined/skills/toolsets/mcp/__init__.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Undefined/skills/toolsets/mcp/__init__.py b/src/Undefined/skills/toolsets/mcp/__init__.py index d9d70269..d2768835 100644 --- a/src/Undefined/skills/toolsets/mcp/__init__.py +++ b/src/Undefined/skills/toolsets/mcp/__init__.py @@ -99,20 +99,21 @@ async def initialize(self) -> None: self._mcp_client = Client(config) # 连接并初始化 - async with self._mcp_client: - if not self._mcp_client.is_connected(): - logger.warning("无法连接到 MCP 服务器") - self._is_initialized = True - return + await self._mcp_client.__aenter__() - # 获取所有工具列表 - tools = await self._mcp_client.list_tools() + if not self._mcp_client.is_connected(): + logger.warning("无法连接到 MCP 服务器") + self._is_initialized = True + return - # 转换每个工具为 toolsets 格式 - for tool in tools: - await self._register_tool(tool) + # 获取所有工具列表 + tools = await self._mcp_client.list_tools() - logger.info(f"MCP 工具集初始化完成,共加载 {len(tools)} 个工具") + # 转换每个工具为 toolsets 格式 + for tool in tools: + await self._register_tool(tool) + + logger.info(f"MCP 工具集初始化完成,共加载 {len(tools)} 个工具") except ImportError: logger.error("fastmcp 库未安装,MCP 功能将不可用") @@ -249,7 +250,8 @@ async def close(self) -> None: logger.info("正在关闭 MCP 客户端连接...") if self._mcp_client: try: - # FastMCP Client 使用 context manager,连接会自动关闭 + # 手动调用 context manager 的退出方法 + await self._mcp_client.__aexit__(None, None, None) logger.debug("已关闭 MCP 客户端连接") except Exception as e: logger.warning(f"关闭 MCP 客户端连接时出错: {e}")