import os import json import re from typing import Any, Dict, List, Tuple from utils.logger import get_logger import yaml logger = get_logger("mcp.SkillLoader") class SkillLoader: """加载和解析 SKILL.md 文件""" @staticmethod 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" 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 skills[skill_info['name']] = skill_info return skills @staticmethod def load_skill(filepath: str) -> Dict[str, Any]: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() skill_info = SkillLoader.parse_skill(content) return skill_info @staticmethod def parse_md_frontmatter(content: str) -> Dict[str, Any]: # 使用正则表达式提取 frontmatter 部分 frontmatter_match = re.search(r'^---\n(.*?)\n---', content, re.DOTALL | re.MULTILINE) if frontmatter_match: frontmatter_content = frontmatter_match.group(1).strip() # 使用 PyYAML 将 frontmatter 字符串解析为字典 frontmatter_data = yaml.safe_load(frontmatter_content) return frontmatter_data else: return {} @staticmethod def parse_skill(content: str) -> Dict[str, Any]: return SkillLoader.parse_md_frontmatter(content) lines = content.strip().splitlines() skill_info = { 'name': lines[0].replace('# ', '').strip(), 'description': lines[1].replace('## Description\n', '').strip(), 'parameters': {}, 'example': None, } # 解析参数 param_section = False for line in lines[2:]: if line.startswith('## Parameters'): param_section = True continue if param_section: if line.startswith('## Example'): break if line.startswith('-'): param_line = line[1:].strip().split(':') if len(param_line) == 2: param_name = param_line[0].strip() param_desc = param_line[1].strip() skill_info['parameters'][param_name] = param_desc # 解析示例 if '## Example' in content: example_start = content.index('## Example') + len('## Example\n') example_json = content[example_start:].strip().split('\n```')[0].strip() skill_info['example'] = json.loads(example_json) return skill_info