From 38dcc420b472d01525e0a8b32519e2759a28d327 Mon Sep 17 00:00:00 2001 From: liusongtao Date: Wed, 15 Apr 2026 16:20:22 +0800 Subject: [PATCH] in devel --- agent/agent.py | 27 +--- config.yaml | 3 +- config/settings.py | 2 +- llm/providers/openai_provider.py | 6 - logs/agent.log | 211 +++++++++++++++++++++++++++++++ main.py | 148 +++++++++++----------- mcp/mcp_server.py | 58 +++++---- mcp/skill_loader.py | 3 +- mcp/skill_registry.py | 36 +++++- tools/calculator.py | 3 +- tools/code_executor.py | 3 +- tools/file_reader.py | 3 +- tools/ssh_docker.py | 3 +- tools/static_analyzer.py | 3 +- tools/tool_generator.py | 28 ---- tools/web_search.py | 3 +- 16 files changed, 363 insertions(+), 177 deletions(-) delete mode 100644 tools/tool_generator.py diff --git a/agent/agent.py b/agent/agent.py index ce5cc11..631a74e 100644 --- a/agent/agent.py +++ b/agent/agent.py @@ -399,32 +399,11 @@ def create_agent() -> tuple[Agent, SkillRegistry]: Returns: (agent, registry) —— registry 需在程序退出时调用 .close() """ - from tools.calculator import CalculatorTool - from tools.code_executor import CodeExecutorTool - from tools.file_reader import FileReaderTool - from tools.ssh_docker import SSHDockerTool - from tools.static_analyzer import StaticAnalyzerTool - from tools.web_search import WebSearchTool - registry = SkillRegistry() - - # 注册本地工具(根据 config.yaml mcp.enabled_tools 过滤) - enabled = settings.mcp.enabled_tools - tool_map = { - "calculator": CalculatorTool, - "web_search": WebSearchTool, - "file_reader": FileReaderTool, - "code_executor": CodeExecutorTool, - "static_analyzer": StaticAnalyzerTool, - "ssh_docker": SSHDockerTool, - } - for name in enabled: - if name in tool_map: - registry.register_local(tool_map[name]()) - + registry.load_local_skills(settings.skills_directory) + registry.load_local_tools() # 连接在线 MCP Skill(来自 config.yaml mcp_skills) - registry.connect_skills() - + registry.connect_mcp_skills() agent = Agent(registry) return agent, registry diff --git a/config.yaml b/config.yaml index 7c3f660..8e2902d 100644 --- a/config.yaml +++ b/config.yaml @@ -16,8 +16,7 @@ llm: stream: false model_path: "" ollama_host: "http://localhost:11434" - -skills_directory: "./skills" # 新增:SKILL.md 文件所在目录 +skills_directory: "C:\\Users\\sonto\\Workspace\\base_agent\\skills\\OpenCLI\\skills" # 新增:SKILL.md 文件所在目录 # ── 本地 MCP Server 配置 ─────────────────────────────────────── mcp: server_name: "DemoMCPServer" diff --git a/config/settings.py b/config/settings.py index a9c90aa..0df46aa 100644 --- a/config/settings.py +++ b/config/settings.py @@ -375,7 +375,7 @@ class ConfigLoader: memory=cls._build_memory(raw.get("memory", {})), logging=cls._build_logging(raw.get("logging", {})), agent=cls._build_agent(raw.get("agent", {})), - skills=raw.get("skills", []) + skills_directory=raw.get("skills_directory", "") ) # ── LLM ─────────────────────────────────────────────────── diff --git a/llm/providers/openai_provider.py b/llm/providers/openai_provider.py index 3351350..219095c 100644 --- a/llm/providers/openai_provider.py +++ b/llm/providers/openai_provider.py @@ -70,12 +70,6 @@ class OpenAIProvider(BaseProvider): 3. 当后续步骤依赖前步结果时,先完成前步再继续 4. 每次只规划并调用当前最合适的工具 5. 所有工具执行完毕后,整合结果给出最终回复 - -## 重要规则 -- 数学计算必须使用 calculator 工具,不要自行计算 -- 需要实时信息时使用 web_search 工具 -- 文件操作使用 file_reader 工具 -- 代码执行使用 code_executor 工具 """ # 回复生成系统 Prompt diff --git a/logs/agent.log b/logs/agent.log index 10b9c49..a2a66bd 100644 --- a/logs/agent.log +++ b/logs/agent.log @@ -6140,3 +6140,214 @@ The function `get_system_name()` uses `platform.system()` to determine the syste 重试 : 2 次 2026-04-13 16:12:50 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 2026-04-13 16:12:50 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=48433 +2026-04-15 15:34:11 [WARNING ] agent.TOOL.SSHDocker │ ⚠️ paramiko 未安装,请执行: pip install paramiko>=3.0.0 +2026-04-15 15:34:11 [WARNING ] agent.mcp.SkillLoader │ 未在opencli-autofix发现SKILL.md文件 +2026-04-15 15:34:11 [WARNING ] agent.mcp.SkillLoader │ 未在opencli-browser发现SKILL.md文件 +2026-04-15 15:34:11 [WARNING ] agent.mcp.SkillLoader │ 未在opencli-explorer发现SKILL.md文件 +2026-04-15 15:34:11 [WARNING ] agent.mcp.SkillLoader │ 未在opencli-oneshot发现SKILL.md文件 +2026-04-15 15:34:11 [WARNING ] agent.mcp.SkillLoader │ 未在opencli-usage发现SKILL.md文件 +2026-04-15 15:34:11 [WARNING ] agent.mcp.SkillLoader │ 未在smart-search发现SKILL.md文件 +2026-04-15 15:34:11 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: calculator +2026-04-15 15:34:11 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: web_search +2026-04-15 15:34:11 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: file_reader +2026-04-15 15:34:11 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: code_executor +2026-04-15 15:34:11 [INFO ] agent.MCP.SkillRegistry │ 🌐 开始连接在线 MCP Skills,数量=1 +2026-04-15 15:34:11 [INFO ] agent.MCP.SkillClient │ 🌐 连接在线 MCP Skill: [hexstrike-ai] + 传输协议: stdio + 地址 : python3 + 超时 : 300s + 重试 : 2 次 +2026-04-15 15:34:11 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:34:11 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=19704 +2026-04-15 15:34:11 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 1/3),1s 后重试: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:34:12 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:34:12 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:34:13 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=14668 +2026-04-15 15:34:13 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 2/3),2s 后重试: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:34:15 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:34:15 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:34:15 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=13920 +2026-04-15 15:34:15 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:34:15 [ERROR ] agent.MCP.SkillRegistry │ ❌ Skill [hexstrike-ai] 连接失败,跳过 + 错误: ❌ MCP Skill [hexstrike-ai] 连接失败(已重试 2 次) + 最后错误: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:34:15 [DEBUG ] agent.MCP.SkillClient │ 🔌 MCP Skill [hexstrike-ai] 已断开 +2026-04-15 15:34:15 [INFO ] agent.MCP.SkillRegistry │ 📊 SkillRegistry 初始化完成 + 本地工具 : 4 个 ['calculator', 'web_search', 'file_reader', 'code_executor'] + 远端工具 : 0 个 [] +2026-04-15 15:34:16 [INFO ] agent.Agent │ 🤖 Agent 初始化完成 + LLM : openai / gpt-4o + 工具总数 : 4 个 + 最大步数 : 10 + 工具列表 : + 🔵 [local ] calculator + 🔵 [local ] web_search + 🔵 [local ] file_reader + 🔵 [local ] code_executor +2026-04-15 15:35:21 [INFO ] agent.MCP.SkillRegistry │ 🔌 SkillRegistry 已关闭所有连接 +2026-04-15 15:35:23 [WARNING ] agent.TOOL.SSHDocker │ ⚠️ paramiko 未安装,请执行: pip install paramiko>=3.0.0 +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-autofix +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-browser +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-explorer +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-oneshot +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-usage +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: smart-search +2026-04-15 15:35:23 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: calculator +2026-04-15 15:35:23 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: web_search +2026-04-15 15:35:23 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: file_reader +2026-04-15 15:35:23 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: code_executor +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillRegistry │ 🌐 开始连接在线 MCP Skills,数量=1 +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillClient │ 🌐 连接在线 MCP Skill: [hexstrike-ai] + 传输协议: stdio + 地址 : python3 + 超时 : 300s + 重试 : 2 次 +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:35:23 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=19588 +2026-04-15 15:35:23 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 1/3),1s 后重试: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:35:24 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:35:24 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:35:24 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=19208 +2026-04-15 15:35:24 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 2/3),2s 后重试: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:35:26 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:35:26 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:35:26 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=19680 +2026-04-15 15:35:26 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:35:26 [ERROR ] agent.MCP.SkillRegistry │ ❌ Skill [hexstrike-ai] 连接失败,跳过 + 错误: ❌ MCP Skill [hexstrike-ai] 连接失败(已重试 2 次) + 最后错误: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:35:26 [DEBUG ] agent.MCP.SkillClient │ 🔌 MCP Skill [hexstrike-ai] 已断开 +2026-04-15 15:35:26 [INFO ] agent.MCP.SkillRegistry │ 📊 SkillRegistry 初始化完成 + 本地工具 : 4 个 ['calculator', 'web_search', 'file_reader', 'code_executor'] + 远端工具 : 6 个 ['opencli-autofix', 'opencli-browser', 'opencli-explorer', 'opencli-oneshot', 'opencli-usage', 'smart-search'] +2026-04-15 15:44:33 [WARNING ] agent.TOOL.SSHDocker │ ⚠️ paramiko 未安装,请执行: pip install paramiko>=3.0.0 +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-autofix +2026-04-15 15:44:33 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-autofix', 'description': 'Automatically fix broken OpenCLI adapters when commands fail. Load this skill when an opencli command fails — it guides you through diagnosing the failure via OPENCLI_DIAGNOSTIC, patching the adapter, retrying, and filing an upstream GitHub issue after a verified fix. Works with any AI agent.', 'allowed-tools': 'Bash(opencli:*), Bash(gh:*), Read, Edit, Write'} +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-browser +2026-04-15 15:44:33 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-browser', 'description': 'Make websites accessible for AI agents. Navigate, click, type, extract, wait — using Chrome with existing login sessions. No LLM API key needed.', 'allowed-tools': 'Bash(opencli:*), Read, Edit, Write'} +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-explorer +2026-04-15 15:44:33 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-explorer', 'description': 'Use when creating a new OpenCLI adapter from scratch, adding support for a new website or platform, exploring a site\'s API endpoints via browser DevTools, or when a user asks to automatically generate a CLI for a website (e.g. "帮我生成 xxx.com 的 cli"). Covers automated generation, API discovery workflow, authentication strategy selection, TS adapter writing, and testing.', 'tags': ['opencli', 'adapter', 'browser', 'api-discovery', 'cli', 'web-scraping', 'automation', 'generate']} +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-oneshot +2026-04-15 15:44:33 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-oneshot', 'description': 'Use when quickly generating a single OpenCLI command from a specific URL and goal description. 4-step process — open page, capture API, write TS adapter, test. For full site exploration, use opencli-explorer instead.', 'tags': ['opencli', 'adapter', 'quick-start', 'ts', 'cli', 'one-shot', 'automation']} +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-usage +2026-04-15 15:44:33 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-usage', 'description': 'Use when running OpenCLI commands to interact with websites (Bilibili, Twitter, Reddit, Xiaohongshu, etc.), desktop apps (Cursor, Notion), or public APIs (HackerNews, arXiv). Covers installation, command reference, and output formats for 87+ adapters.', 'version': '1.7.0', 'author': 'jackwener', 'tags': ['opencli', 'cli', 'browser', 'web', 'chrome-extension', 'cdp', 'bilibili', 'twitter', 'reddit', 'xiaohongshu', 'github', 'youtube', 'AI', 'agent', 'automation']} +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: smart-search +2026-04-15 15:44:33 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'smart-search', 'description': '基于 opencli 命令的智能搜索路由器。当用户想要搜索、查询、查找或研究信息时,尤其是涉及指定网站、社交媒体、技术资料、新闻、购物、旅游、求职、金融或中文内容时,务必使用此 skill'} +2026-04-15 15:44:33 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: calculator +2026-04-15 15:44:33 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: web_search +2026-04-15 15:44:33 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: file_reader +2026-04-15 15:44:33 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: code_executor +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillRegistry │ 🌐 开始连接在线 MCP Skills,数量=1 +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillClient │ 🌐 连接在线 MCP Skill: [hexstrike-ai] + 传输协议: stdio + 地址 : python3 + 超时 : 300s + 重试 : 2 次 +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:44:33 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=19376 +2026-04-15 15:44:33 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 1/3),1s 后重试: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:44:34 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:44:34 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:44:34 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=18048 +2026-04-15 15:44:34 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 2/3),2s 后重试: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:44:36 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:44:36 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 15:44:36 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=19960 +2026-04-15 15:44:36 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 15:44:36 [ERROR ] agent.MCP.SkillRegistry │ ❌ Skill [hexstrike-ai] 连接失败,跳过 + 错误: ❌ MCP Skill [hexstrike-ai] 连接失败(已重试 2 次) + 最后错误: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 15:44:36 [DEBUG ] agent.MCP.SkillClient │ 🔌 MCP Skill [hexstrike-ai] 已断开 +2026-04-15 15:44:36 [INFO ] agent.MCP.SkillRegistry │ 📊 SkillRegistry 初始化完成 + 本地工具 : 4 个 ['calculator', 'web_search', 'file_reader', 'code_executor'] + 远端工具 : 0 个 [] +2026-04-15 15:44:37 [INFO ] agent.Agent │ 🤖 Agent 初始化完成 + LLM : openai / gpt-4o + 工具总数 : 4 个 + 最大步数 : 10 + 工具列表 : + 🔵 [local ] calculator + 🔵 [local ] web_search + 🔵 [local ] file_reader + 🔵 [local ] code_executor +2026-04-15 16:09:20 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-autofix +2026-04-15 16:09:20 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-autofix', 'description': 'Automatically fix broken OpenCLI adapters when commands fail. Load this skill when an opencli command fails — it guides you through diagnosing the failure via OPENCLI_DIAGNOSTIC, patching the adapter, retrying, and filing an upstream GitHub issue after a verified fix. Works with any AI agent.', 'allowed-tools': 'Bash(opencli:*), Bash(gh:*), Read, Edit, Write'} +2026-04-15 16:09:20 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-browser +2026-04-15 16:09:20 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-browser', 'description': 'Make websites accessible for AI agents. Navigate, click, type, extract, wait — using Chrome with existing login sessions. No LLM API key needed.', 'allowed-tools': 'Bash(opencli:*), Read, Edit, Write'} +2026-04-15 16:09:20 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-explorer +2026-04-15 16:09:20 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-explorer', 'description': 'Use when creating a new OpenCLI adapter from scratch, adding support for a new website or platform, exploring a site\'s API endpoints via browser DevTools, or when a user asks to automatically generate a CLI for a website (e.g. "帮我生成 xxx.com 的 cli"). Covers automated generation, API discovery workflow, authentication strategy selection, TS adapter writing, and testing.', 'tags': ['opencli', 'adapter', 'browser', 'api-discovery', 'cli', 'web-scraping', 'automation', 'generate']} +2026-04-15 16:09:20 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-oneshot +2026-04-15 16:09:20 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-oneshot', 'description': 'Use when quickly generating a single OpenCLI command from a specific URL and goal description. 4-step process — open page, capture API, write TS adapter, test. For full site exploration, use opencli-explorer instead.', 'tags': ['opencli', 'adapter', 'quick-start', 'ts', 'cli', 'one-shot', 'automation']} +2026-04-15 16:09:20 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-usage +2026-04-15 16:09:20 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-usage', 'description': 'Use when running OpenCLI commands to interact with websites (Bilibili, Twitter, Reddit, Xiaohongshu, etc.), desktop apps (Cursor, Notion), or public APIs (HackerNews, arXiv). Covers installation, command reference, and output formats for 87+ adapters.', 'version': '1.7.0', 'author': 'jackwener', 'tags': ['opencli', 'cli', 'browser', 'web', 'chrome-extension', 'cdp', 'bilibili', 'twitter', 'reddit', 'xiaohongshu', 'github', 'youtube', 'AI', 'agent', 'automation']} +2026-04-15 16:09:20 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: smart-search +2026-04-15 16:09:20 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'smart-search', 'description': '基于 opencli 命令的智能搜索路由器。当用户想要搜索、查询、查找或研究信息时,尤其是涉及指定网站、社交媒体、技术资料、新闻、购物、旅游、求职、金融或中文内容时,务必使用此 skill'} +2026-04-15 16:09:28 [INFO ] agent.MCP.SkillRegistry │ 🔧 注册本地工具: ['calculator', 'web_search', 'file_reader', 'code_executor'] +2026-04-15 16:10:46 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-autofix +2026-04-15 16:10:46 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-autofix', 'description': 'Automatically fix broken OpenCLI adapters when commands fail. Load this skill when an opencli command fails — it guides you through diagnosing the failure via OPENCLI_DIAGNOSTIC, patching the adapter, retrying, and filing an upstream GitHub issue after a verified fix. Works with any AI agent.', 'allowed-tools': 'Bash(opencli:*), Bash(gh:*), Read, Edit, Write'} +2026-04-15 16:10:46 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-browser +2026-04-15 16:10:46 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-browser', 'description': 'Make websites accessible for AI agents. Navigate, click, type, extract, wait — using Chrome with existing login sessions. No LLM API key needed.', 'allowed-tools': 'Bash(opencli:*), Read, Edit, Write'} +2026-04-15 16:10:46 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-explorer +2026-04-15 16:10:46 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-explorer', 'description': 'Use when creating a new OpenCLI adapter from scratch, adding support for a new website or platform, exploring a site\'s API endpoints via browser DevTools, or when a user asks to automatically generate a CLI for a website (e.g. "帮我生成 xxx.com 的 cli"). Covers automated generation, API discovery workflow, authentication strategy selection, TS adapter writing, and testing.', 'tags': ['opencli', 'adapter', 'browser', 'api-discovery', 'cli', 'web-scraping', 'automation', 'generate']} +2026-04-15 16:10:46 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-oneshot +2026-04-15 16:10:46 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-oneshot', 'description': 'Use when quickly generating a single OpenCLI command from a specific URL and goal description. 4-step process — open page, capture API, write TS adapter, test. For full site exploration, use opencli-explorer instead.', 'tags': ['opencli', 'adapter', 'quick-start', 'ts', 'cli', 'one-shot', 'automation']} +2026-04-15 16:10:46 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-usage +2026-04-15 16:10:46 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-usage', 'description': 'Use when running OpenCLI commands to interact with websites (Bilibili, Twitter, Reddit, Xiaohongshu, etc.), desktop apps (Cursor, Notion), or public APIs (HackerNews, arXiv). Covers installation, command reference, and output formats for 87+ adapters.', 'version': '1.7.0', 'author': 'jackwener', 'tags': ['opencli', 'cli', 'browser', 'web', 'chrome-extension', 'cdp', 'bilibili', 'twitter', 'reddit', 'xiaohongshu', 'github', 'youtube', 'AI', 'agent', 'automation']} +2026-04-15 16:10:46 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: smart-search +2026-04-15 16:10:46 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'smart-search', 'description': '基于 opencli 命令的智能搜索路由器。当用户想要搜索、查询、查找或研究信息时,尤其是涉及指定网站、社交媒体、技术资料、新闻、购物、旅游、求职、金融或中文内容时,务必使用此 skill'} +2026-04-15 16:10:46 [INFO ] agent.MCP.SkillRegistry │ 🔧 注册本地工具: ['calculator', 'web_search', 'file_reader', 'code_executor'] +2026-04-15 16:10:53 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: calculator +2026-04-15 16:10:58 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: web_search +2026-04-15 16:10:58 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: file_reader +2026-04-15 16:10:58 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: code_executor +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-autofix +2026-04-15 16:12:30 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-autofix', 'description': 'Automatically fix broken OpenCLI adapters when commands fail. Load this skill when an opencli command fails — it guides you through diagnosing the failure via OPENCLI_DIAGNOSTIC, patching the adapter, retrying, and filing an upstream GitHub issue after a verified fix. Works with any AI agent.', 'allowed-tools': 'Bash(opencli:*), Bash(gh:*), Read, Edit, Write'} +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-browser +2026-04-15 16:12:30 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-browser', 'description': 'Make websites accessible for AI agents. Navigate, click, type, extract, wait — using Chrome with existing login sessions. No LLM API key needed.', 'allowed-tools': 'Bash(opencli:*), Read, Edit, Write'} +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-explorer +2026-04-15 16:12:30 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-explorer', 'description': 'Use when creating a new OpenCLI adapter from scratch, adding support for a new website or platform, exploring a site\'s API endpoints via browser DevTools, or when a user asks to automatically generate a CLI for a website (e.g. "帮我生成 xxx.com 的 cli"). Covers automated generation, API discovery workflow, authentication strategy selection, TS adapter writing, and testing.', 'tags': ['opencli', 'adapter', 'browser', 'api-discovery', 'cli', 'web-scraping', 'automation', 'generate']} +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-oneshot +2026-04-15 16:12:30 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-oneshot', 'description': 'Use when quickly generating a single OpenCLI command from a specific URL and goal description. 4-step process — open page, capture API, write TS adapter, test. For full site exploration, use opencli-explorer instead.', 'tags': ['opencli', 'adapter', 'quick-start', 'ts', 'cli', 'one-shot', 'automation']} +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: opencli-usage +2026-04-15 16:12:30 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'opencli-usage', 'description': 'Use when running OpenCLI commands to interact with websites (Bilibili, Twitter, Reddit, Xiaohongshu, etc.), desktop apps (Cursor, Notion), or public APIs (HackerNews, arXiv). Covers installation, command reference, and output formats for 87+ adapters.', 'version': '1.7.0', 'author': 'jackwener', 'tags': ['opencli', 'cli', 'browser', 'web', 'chrome-extension', 'cdp', 'bilibili', 'twitter', 'reddit', 'xiaohongshu', 'github', 'youtube', 'AI', 'agent', 'automation']} +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 📦 加载技能: smart-search +2026-04-15 16:12:30 [WARNING ] agent.MCP.SkillRegistry │ ⚠️ 工具实例缺少 name 属性,跳过: {'name': 'smart-search', 'description': '基于 opencli 命令的智能搜索路由器。当用户想要搜索、查询、查找或研究信息时,尤其是涉及指定网站、社交媒体、技术资料、新闻、购物、旅游、求职、金融或中文内容时,务必使用此 skill'} +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 🔧 注册本地工具: ['calculator', 'web_search', 'file_reader', 'code_executor'] +2026-04-15 16:12:30 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: calculator +2026-04-15 16:12:30 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: web_search +2026-04-15 16:12:30 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: file_reader +2026-04-15 16:12:30 [DEBUG ] agent.MCP.SkillRegistry │ 📌 注册本地工具: code_executor +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillRegistry │ 🌐 开始连接在线 MCP Skills,数量=1 +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillClient │ 🌐 连接在线 MCP Skill: [hexstrike-ai] + 传输协议: stdio + 地址 : python3 + 超时 : 300s + 重试 : 2 次 +2026-04-15 16:12:30 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 16:12:33 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=18196 +2026-04-15 16:12:37 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 1/3),1s 后重试: [Errno 22] Invalid argument +2026-04-15 16:12:38 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 16:12:38 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 16:12:38 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=14612 +2026-04-15 16:12:38 [WARNING ] agent.MCP.SkillClient │ ⚠️ 连接失败 (attempt 2/3),2s 后重试: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 16:12:40 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 16:12:40 [INFO ] agent.MCP.SkillClient │ 🔌 stdio 启动子进程: python3 /Users/sontolau/Applications/hexstrike-ai/hexstrike_mcp.py --server http://localhost:8999 +2026-04-15 16:12:40 [INFO ] agent.MCP.SkillClient │ ✅ stdio 子进程已启动 PID=7028 +2026-04-15 16:12:40 [DEBUG ] agent.MCP.SkillClient │ 🔌 stdio 子进程已关闭 skill=hexstrike-ai +2026-04-15 16:12:40 [ERROR ] agent.MCP.SkillRegistry │ ❌ Skill [hexstrike-ai] 连接失败,跳过 + 错误: ❌ MCP Skill [hexstrike-ai] 连接失败(已重试 2 次) + 最后错误: stdio 子进程无响应 skill=hexstrike-ai method=initialize +2026-04-15 16:12:40 [DEBUG ] agent.MCP.SkillClient │ 🔌 MCP Skill [hexstrike-ai] 已断开 +2026-04-15 16:12:40 [INFO ] agent.MCP.SkillRegistry │ 📊 SkillRegistry 初始化完成 + 本地工具 : 4 个 ['calculator', 'web_search', 'file_reader', 'code_executor'] + 远端工具 : 0 个 [] +2026-04-15 16:12:42 [INFO ] agent.Agent │ 🤖 Agent 初始化完成 + LLM : openai / gpt-4o + 工具总数 : 4 个 + 最大步数 : 10 + 工具列表 : + 🔵 [local ] calculator + 🔵 [local ] web_search + 🔵 [local ] file_reader + 🔵 [local ] code_executor +2026-04-15 16:19:35 [INFO ] agent.MCP.SkillRegistry │ 🔌 SkillRegistry 已关闭所有连接 diff --git a/main.py b/main.py index ecece98..90844e0 100644 --- a/main.py +++ b/main.py @@ -60,78 +60,78 @@ def run_mcp_server() -> None: server.run_stdio() -def run_check() -> None: - """检查配置和依赖完整性""" - print("=" * 60) - print(" 🔍 项目依赖检查") - print("=" * 60) - - checks = [ - ("pyyaml", "yaml", "pip install pyyaml"), - ("openai", "openai", "pip install openai>=1.0.0"), - ("httpx", "httpx", "pip install httpx>=0.27.0"), - ("httpx-sse", "httpx_sse", "pip install httpx-sse>=0.4.0"), - ("paramiko", "paramiko", "pip install paramiko>=3.0.0"), - ] - - all_ok = True - for pkg_name, import_name, install_cmd in checks: - try: - __import__(import_name) - print(f" ✅ {pkg_name:<15} 已安装") - except ImportError: - print(f" ❌ {pkg_name:<15} 未安装 → {install_cmd}") - all_ok = False - - print() - - # 配置检查 - try: - from config.settings import settings - print(" ✅ config/settings.py 加载成功") - print(f" LLM : {settings.llm.provider} / {settings.llm.model_name}") - print(f" 本地工具: {settings.mcp.enabled_tools}") - skills = settings.enabled_mcp_skills - if skills: - print(f" 在线Skill: {[s.name for s in skills]}") - else: - print(" 在线Skill: (未配置)") - except Exception as e: - print(f" ❌ 配置加载失败: {e}") - all_ok = False - - print() - - # 工具注册检查 - try: - from mcp.skill_registry import SkillRegistry - from tools.calculator import CalculatorTool - from tools.code_executor import CodeExecutorTool - from tools.file_reader import FileReaderTool - from tools.ssh_docker import SSHDockerTool - from tools.static_analyzer import StaticAnalyzerTool - from tools.web_search import WebSearchTool - - registry = SkillRegistry() - registry.register_local_many( - CalculatorTool(), WebSearchTool(), FileReaderTool(), - CodeExecutorTool(), StaticAnalyzerTool(), SSHDockerTool(), - ) - tools = registry.list_all_tools() - print(f" ✅ 本地工具注册 共 {len(tools)} 个:") - for t in tools: - print(f" 🔵 {t['name']}: {t['description'][:50]}") - except Exception as e: - print(f" ❌ 工具注册失败: {e}") - all_ok = False - - print() - print("=" * 60) - if all_ok: - print(" ✅ 所有检查通过,项目可正常运行") - else: - print(" ⚠️ 存在问题,请按提示安装缺失依赖") - print("=" * 60) +# def run_check() -> None: +# """检查配置和依赖完整性""" +# print("=" * 60) +# print(" 🔍 项目依赖检查") +# print("=" * 60) +# +# checks = [ +# ("pyyaml", "yaml", "pip install pyyaml"), +# ("openai", "openai", "pip install openai>=1.0.0"), +# ("httpx", "httpx", "pip install httpx>=0.27.0"), +# ("httpx-sse", "httpx_sse", "pip install httpx-sse>=0.4.0"), +# ("paramiko", "paramiko", "pip install paramiko>=3.0.0"), +# ] +# +# all_ok = True +# for pkg_name, import_name, install_cmd in checks: +# try: +# __import__(import_name) +# print(f" ✅ {pkg_name:<15} 已安装") +# except ImportError: +# print(f" ❌ {pkg_name:<15} 未安装 → {install_cmd}") +# all_ok = False +# +# print() +# +# # 配置检查 +# try: +# from config.settings import settings +# print(" ✅ config/settings.py 加载成功") +# print(f" LLM : {settings.llm.provider} / {settings.llm.model_name}") +# print(f" 本地工具: {settings.mcp.enabled_tools}") +# skills = settings.enabled_mcp_skills +# if skills: +# print(f" 在线Skill: {[s.name for s in skills]}") +# else: +# print(" 在线Skill: (未配置)") +# except Exception as e: +# print(f" ❌ 配置加载失败: {e}") +# all_ok = False +# +# print() +# +# # 工具注册检查 +# try: +# from mcp.skill_registry import SkillRegistry +# from tools.calculator import CalculatorTool +# from tools.code_executor import CodeExecutorTool +# from tools.file_reader import FileReaderTool +# from tools.ssh_docker import SSHDockerTool +# from tools.static_analyzer import StaticAnalyzerTool +# from tools.web_search import WebSearchTool +# +# registry = SkillRegistry() +# registry.register_local_many( +# CalculatorTool(), WebSearchTool(), FileReaderTool(), +# CodeExecutorTool(), StaticAnalyzerTool(), SSHDockerTool(), +# ) +# tools = registry.list_all_tools() +# print(f" ✅ 本地工具注册 共 {len(tools)} 个:") +# for t in tools: +# print(f" 🔵 {t['name']}: {t['description'][:50]}") +# except Exception as e: +# print(f" ❌ 工具注册失败: {e}") +# all_ok = False +# +# print() +# print("=" * 60) +# if all_ok: +# print(" ✅ 所有检查通过,项目可正常运行") +# else: +# print(" ⚠️ 存在问题,请按提示安装缺失依赖") +# print("=" * 60) def main() -> None: @@ -151,8 +151,8 @@ def main() -> None: run_agent() case "mcp": run_mcp_server() - case "check": - run_check() + # case "check": + # run_check() if __name__ == "__main__": diff --git a/mcp/mcp_server.py b/mcp/mcp_server.py index 73882ea..860924d 100644 --- a/mcp/mcp_server.py +++ b/mcp/mcp_server.py @@ -6,30 +6,12 @@ mcp/mcp_server.py import json import sys from typing import Any - from config.settings import settings from mcp.skill_registry import SkillRegistry -from tools.calculator import CalculatorTool -from tools.code_executor import CodeExecutorTool -from tools.file_reader import FileReaderTool -from tools.ssh_docker import SSHDockerTool -from tools.static_analyzer import StaticAnalyzerTool -from tools.web_search import WebSearchTool from utils.logger import get_logger logger = get_logger("MCP.Server") -# 本地工具类映射表 -_LOCAL_TOOL_CLASSES: dict[str, type] = { - "calculator": CalculatorTool, - "web_search": WebSearchTool, - "file_reader": FileReaderTool, - "code_executor": CodeExecutorTool, - "static_analyzer": StaticAnalyzerTool, - "ssh_docker": SSHDockerTool, -} - - class MCPServer: """ 本地 MCP Server @@ -48,17 +30,37 @@ class MCPServer: def _setup(self) -> None: """初始化:注册本地工具 + 连接在线 Skill""" # ── 注册本地工具 ────────────────────────────────────── - enabled = settings.mcp.enabled_tools - logger.info(f"🔧 注册本地工具: {enabled}") - for tool_name in enabled: - cls = _LOCAL_TOOL_CLASSES.get(tool_name) - if cls: - self.registry.register_local(cls()) - else: - logger.warning(f"⚠️ 未知工具: {tool_name},跳过") - + # enabled = settings.mcp.enabled_tools + # logger.info(f"🔧 注册本地工具: {enabled}") + # for tool_name in enabled: + # tool_path = f"tools/{tool_name}.py" + # if not os.path.exists(tool_path): + # continue + # # module_name = filename[:-3] # 去掉 .py 后缀 + # # module_path = os.path.join(directory_path, filename) + # + # # 动态加载模块 + # spec = importlib.util.spec_from_file_location(tool_name, tool_path) + # module = importlib.util.module_from_spec(spec) + # spec.loader.exec_module(module) + # + # if not hasattr(module, "Tool"): + # continue + # + # cls = getattr(module, 'Tool') + # if not isinstance(cls, BaseTool): + # continue + # + # # tool_classes.append(tool_class) + # # cls = _LOCAL_TOOL_CLASSES.get(tool_name) + # if cls: + # self.registry.register_local(cls()) + # else: + # logger.warning(f"⚠️ 未知工具: {tool_name},跳过") + self.registry.load_local_tools() + self.registry.load_local_skills(settings.skills_directory) # ── 连接在线 MCP Skill ──────────────────────────────── - skill_map = self.registry.connect_skills() + skill_map = self.registry.connect_mcp_skills() if skill_map: logger.info( "🌐 在线 Skill 注册汇总:\n" + diff --git a/mcp/skill_loader.py b/mcp/skill_loader.py index 5b9f647..d2655a5 100644 --- a/mcp/skill_loader.py +++ b/mcp/skill_loader.py @@ -14,11 +14,10 @@ class SkillLoader: def load_skills_from_directory(directory: str) -> Dict[str, Any]: skills = {} for skill_directory in os.listdir(directory): - skill_md = f"{skill_directory}/SKILL.md" + skill_md = f"{directory}/{skill_directory}/SKILL.md" if not os.path.isfile(skill_md): logger.warning(f"未在{skill_directory}发现SKILL.md文件") continue - skill_name = os.path.basename(skill_directory) # 去掉 .md 后缀 skill_info = SkillLoader.load_skill(skill_md) if not skill_info: continue diff --git a/mcp/skill_registry.py b/mcp/skill_registry.py index 3eb9043..f994273 100644 --- a/mcp/skill_registry.py +++ b/mcp/skill_registry.py @@ -8,7 +8,8 @@ mcp/skill_registry.py - dispatch() → 根据工具名路由到本地或远端执行 - refresh_skills() → 重新拉取在线 Skill 工具列表 """ - +import importlib +import os import time from dataclasses import dataclass from typing import Any @@ -16,6 +17,7 @@ from typing import Any from config.settings import settings from mcp.mcp_skill_client import MCPSkillClient, RemoteTool, ToolCallResult from mcp.skill_loader import SkillLoader +from tools.base_tool import BaseTool from utils.logger import get_logger logger = get_logger("MCP.SkillRegistry") @@ -82,15 +84,37 @@ class SkillRegistry: self._remote: dict[str, tuple[MCPSkillClient, RemoteTool]] = {} # 在线 Skill 客户端列表(用于生命周期管理) self._clients: list[MCPSkillClient] = [] - # 指定 SKILL.md 文件所在目录 - self.load_skills_from_md(settings.skills_directory) - def load_skills_from_md(self, directory: str) -> None: + + def load_local_skills(self, directory: str) -> None: skills = SkillLoader.load_skills_from_directory(directory) for skill_name, skill_info in skills.items(): logger.info(f"📦 加载技能: {skill_name}") # 将技能注册到远端工具表 - self._remote[skill_name] = skill_info + #self._remote[skill_name] = skill_info + self.register_local(skill_info) + + def load_local_tools(self): + enabled = settings.mcp.enabled_tools + logger.info(f"🔧 注册本地工具: {enabled}") + for tool_name in enabled: + tool_path = f"tools/{tool_name}.py" + if not os.path.exists(tool_path): + continue + # 动态加载模块 + spec = importlib.util.spec_from_file_location(tool_name, tool_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + if not hasattr(module, "Tool"): + continue + cls = getattr(module, 'Tool') + if not issubclass(cls, BaseTool): + continue + if cls: + self.register_local(cls()) + else: + logger.warning(f"⚠️ 未知工具: {tool_name},跳过") + # ── 注册本地工具 ────────────────────────────────────────── @@ -117,7 +141,7 @@ class SkillRegistry: # ── 连接在线 MCP Skill ──────────────────────────────────── - def connect_skills(self) -> dict[str, list[str]]: + def connect_mcp_skills(self) -> dict[str, list[str]]: """ 连接所有 config.yaml 中 enabled=true 的在线 MCP Skill 并将其工具注册到远端工具表 diff --git a/tools/calculator.py b/tools/calculator.py index 71b5713..32659a8 100644 --- a/tools/calculator.py +++ b/tools/calculator.py @@ -9,6 +9,7 @@ import operator from typing import Any from config.settings import settings +from tools.base_tool import BaseTool from utils.logger import get_logger logger = get_logger("TOOL.Calculator") @@ -18,7 +19,7 @@ def _cfg(key: str, fallback=None): return settings.tools['calculator'].get(key, fallback) -class CalculatorTool: +class Tool(BaseTool): name = "calculator" description = ( "执行数学计算,支持四则运算、幂运算、开方、三角函数、对数等。" diff --git a/tools/code_executor.py b/tools/code_executor.py index 84f03b4..419a66b 100644 --- a/tools/code_executor.py +++ b/tools/code_executor.py @@ -12,6 +12,7 @@ import traceback from contextlib import redirect_stderr, redirect_stdout from config.settings import settings +from tools.base_tool import BaseTool from utils.logger import get_logger logger = get_logger("TOOL.CodeExecutor") @@ -21,7 +22,7 @@ def _cfg(key: str, fallback=None): return settings.tools['code_executor'].get(key, fallback) -class CodeExecutorTool: +class Tool(BaseTool): name = "code_executor" description = ( "在安全沙箱中执行 Python 代码片段,返回标准输出和执行结果。" diff --git a/tools/file_reader.py b/tools/file_reader.py index ebd5171..f4c9184 100644 --- a/tools/file_reader.py +++ b/tools/file_reader.py @@ -10,6 +10,7 @@ import json from pathlib import Path from config.settings import settings +from tools.base_tool import BaseTool from utils.logger import get_logger logger = get_logger("TOOL.FileReader") @@ -19,7 +20,7 @@ def _cfg(key: str, fallback=None): return settings.tools['file_reader'].get(key, fallback) -class FileReaderTool: +class Tool(BaseTool): name = "file_reader" description = ( "读取本地文件内容,支持 .txt / .md / .py / .json / .csv / .yaml / .log 等文本文件。" diff --git a/tools/ssh_docker.py b/tools/ssh_docker.py index 3b35bda..4d303ad 100644 --- a/tools/ssh_docker.py +++ b/tools/ssh_docker.py @@ -10,6 +10,7 @@ import time from dataclasses import dataclass, field from config.settings import settings +from tools.base_tool import BaseTool from utils.logger import get_logger logger = get_logger("TOOL.SSHDocker") @@ -324,7 +325,7 @@ class DockerExecutor: # 主工具类 # ════════════════════════════════════════════════════════════════ -class SSHDockerTool: +class Tool(BaseTool): """ SSH 远程 Docker 部署工具 所有配置均通过 settings.tools['ssh_docker'][key] 读取 diff --git a/tools/static_analyzer.py b/tools/static_analyzer.py index 33eadaa..2577f0c 100644 --- a/tools/static_analyzer.py +++ b/tools/static_analyzer.py @@ -13,6 +13,7 @@ from dataclasses import dataclass, field from pathlib import Path from config.settings import settings +from tools.base_tool import BaseTool from utils.logger import get_logger logger = get_logger("TOOL.StaticAnalyzer") @@ -281,7 +282,7 @@ _TOOL_REGISTRY: dict[str, type] = { # 主工具类 # ════════════════════════════════════════════════════════════════ -class StaticAnalyzerTool: +class Tool(BaseTool): """ C/C++ 静态分析工具 所有配置均通过 settings.tools['static_analyzer'][key] 读取 diff --git a/tools/tool_generator.py b/tools/tool_generator.py deleted file mode 100644 index da3d48f..0000000 --- a/tools/tool_generator.py +++ /dev/null @@ -1,28 +0,0 @@ -from tools.base_tool import BaseTool, ToolResult - - -class ToolGeneratorTool(BaseTool): - name = "tool_generator" - description = "生成agent工具代码" - parameters = { - "name": { - "type": "string", - "description": "tool name", - }, - "description": { - "type": "string", - "description": "tool description" - - }, - "parameters": { - "type": "object", - "description": """tool parameters descriptions""" - }, - "code": { - "type": "string", - "description": "the code that the LLM generated" - } - } - - def execute(self, name: str, description: str, parameters: dict, code: str) -> ToolResult: - pass diff --git a/tools/web_search.py b/tools/web_search.py index 890b600..3dd38d9 100644 --- a/tools/web_search.py +++ b/tools/web_search.py @@ -9,6 +9,7 @@ import time from dataclasses import dataclass, field from config.settings import settings +from tools.base_tool import BaseTool from utils.logger import get_logger logger = get_logger("TOOL.WebSearch") @@ -29,7 +30,7 @@ class SearchResult: return f"[{self.rank}] {self.title}\n {self.url}\n {self.snippet}" -class WebSearchTool: +class Tool(BaseTool): name = "web_search" description = ( "在互联网上搜索信息,返回相关网页的标题、链接和摘要。"