170 lines
4.3 KiB
Python
170 lines
4.3 KiB
Python
"""MCP Skill 加载器 - Phase 9.2
|
|
|
|
从 MCP (Model Context Protocol) 服务器发现和加载 Skills。
|
|
"""
|
|
|
|
import os
|
|
from typing import Any
|
|
|
|
from app.agents.skills.metadata import SkillMetadata
|
|
|
|
|
|
class MCPSkillLoader:
|
|
"""MCP Skill 加载器
|
|
|
|
从 MCP 服务器发现可用的 Skills。
|
|
"""
|
|
|
|
def __init__(self, mcp_servers: list[dict[str, Any]] | None = None):
|
|
"""
|
|
Args:
|
|
mcp_servers: MCP 服务器列表,每项包含 name, command, env 等
|
|
"""
|
|
self.mcp_servers = mcp_servers or []
|
|
self._discovered_skills: dict[str, SkillMetadata] = {}
|
|
|
|
def discover_skills(self) -> list[SkillMetadata]:
|
|
"""从所有配置的 MCP 服务器发现 Skills
|
|
|
|
Returns:
|
|
发现的 Skill 列表
|
|
"""
|
|
skills = []
|
|
|
|
for server in self.mcp_servers:
|
|
server_skills = self._discover_from_server(server)
|
|
skills.extend(server_skills)
|
|
|
|
return skills
|
|
|
|
def _discover_from_server(self, server: dict[str, Any]) -> list[SkillMetadata]:
|
|
"""从单个 MCP 服务器发现 Skills
|
|
|
|
Args:
|
|
server: 服务器配置
|
|
|
|
Returns:
|
|
Skill 列表
|
|
"""
|
|
skills = []
|
|
server_name = server.get("name", "unknown")
|
|
|
|
# 模拟从 MCP 服务器获取工具列表
|
|
# 实际实现时,这里会调用 MCP 服务器的 list_tools 接口
|
|
try:
|
|
tools = self._call_mcp_list_tools(server)
|
|
for tool in tools:
|
|
skill = self._tool_to_skill(tool, server_name)
|
|
if skill:
|
|
skills.append(skill)
|
|
self._discovered_skills[skill.name] = skill
|
|
except Exception:
|
|
pass
|
|
|
|
return skills
|
|
|
|
def _call_mcp_list_tools(self, server: dict[str, Any]) -> list[dict[str, Any]]:
|
|
"""调用 MCP 服务器的 list_tools 接口
|
|
|
|
Args:
|
|
server: 服务器配置
|
|
|
|
Returns:
|
|
工具列表
|
|
"""
|
|
# TODO: 实现实际的 MCP 协议调用
|
|
# 目前返回空列表,实际使用时需要实现 MCP 客户端
|
|
return []
|
|
|
|
def _tool_to_skill(self, tool: dict[str, Any], server: str) -> SkillMetadata | None:
|
|
"""将 MCP 工具转换为 Skill
|
|
|
|
Args:
|
|
tool: MCP 工具定义
|
|
server: 服务器名
|
|
|
|
Returns:
|
|
Skill 元数据或 None
|
|
"""
|
|
tool_name = tool.get("name")
|
|
if not tool_name:
|
|
return None
|
|
|
|
return SkillMetadata(
|
|
id=f"mcp_{server}_{tool_name}",
|
|
name=f"{server}:{tool_name}",
|
|
description=tool.get("description", f"MCP tool: {tool_name}"),
|
|
version="1.0.0",
|
|
content=self._generate_skill_content(tool),
|
|
triggers=[f"@{server}", f"/{tool_name}"],
|
|
tools=[tool_name],
|
|
tags=["mcp", server],
|
|
enabled=True,
|
|
)
|
|
|
|
def _generate_skill_content(self, tool: dict[str, Any]) -> str:
|
|
"""生成 Skill 内容
|
|
|
|
Args:
|
|
tool: MCP 工具定义
|
|
|
|
Returns:
|
|
Skill 内容字符串
|
|
"""
|
|
name = tool.get("name", "unknown")
|
|
description = tool.get("description", "No description")
|
|
input_schema = tool.get("inputSchema", {})
|
|
|
|
content = f"""# MCP Tool: {name}
|
|
|
|
**Description**: {description}
|
|
|
|
**Server**: {tool.get("server", "unknown")}
|
|
|
|
**Input Schema**:
|
|
```json
|
|
{input_schema}
|
|
```
|
|
|
|
**Usage**:
|
|
Use the `/{name}` command or `@{tool.get("server", "server")}` to invoke this tool.
|
|
|
|
**Examples**:
|
|
```
|
|
/{name} arg1=value1 arg2=value2
|
|
@{tool.get("server", "server")} {name} --arg1 value1
|
|
```
|
|
"""
|
|
return content
|
|
|
|
def get_skill(self, name: str) -> SkillMetadata | None:
|
|
"""获取已发现的 Skill
|
|
|
|
Args:
|
|
name: Skill 名称
|
|
|
|
Returns:
|
|
Skill 元数据或 None
|
|
"""
|
|
return self._discovered_skills.get(name)
|
|
|
|
def list_skills(self) -> list[SkillMetadata]:
|
|
"""列出所有已发现的 Skills
|
|
|
|
Returns:
|
|
Skill 列表
|
|
"""
|
|
return list(self._discovered_skills.values())
|
|
|
|
|
|
# 全局加载器
|
|
_loader: MCPSkillLoader | None = None
|
|
|
|
|
|
def get_mcp_skill_loader() -> MCPSkillLoader:
|
|
"""获取全局 MCP Skill 加载器"""
|
|
global _loader
|
|
if _loader is None:
|
|
_loader = MCPSkillLoader()
|
|
return _loader
|