Skip to main content
Glama
by fkesheh
file_service.pyโ€ข6.45 kB
"""File management service.""" from typing import Any, Dict, List from skill_mcp.core.config import MAX_FILE_SIZE, SKILL_METADATA_FILE, SKILLS_DIR from skill_mcp.core.exceptions import ( FileNotFoundError, FileTooBigError, ProtectedFileError, SkillNotFoundError, ) from skill_mcp.utils.path_utils import validate_path class FileService: """Service for managing skill files.""" @staticmethod def list_skill_files(skill_name: str) -> List[Dict[str, Any]]: """ List all files in a skill directory recursively. Args: skill_name: Name of the skill Returns: List of file information dictionaries Raises: SkillNotFoundError: If skill doesn't exist """ skill_dir = SKILLS_DIR / skill_name if not skill_dir.exists(): raise SkillNotFoundError(f"Skill '{skill_name}' does not exist") if not skill_dir.is_dir(): raise SkillNotFoundError(f"'{skill_name}' is not a directory") files = [] for item in sorted(skill_dir.rglob("*")): if item.is_file(): rel_path = item.relative_to(skill_dir) stat = item.stat() files.append( { "path": str(rel_path), "size": stat.st_size, "type": "file", "modified": stat.st_mtime, } ) return files @staticmethod def read_file(skill_name: str, file_path: str) -> str: """ Read content of a skill file. Args: skill_name: Name of the skill file_path: Relative path to the file Returns: File content as string Raises: InvalidPathError: If path is invalid FileNotFoundError: If file doesn't exist FileTooBigError: If file exceeds size limit """ full_path = validate_path(skill_name, file_path) if not full_path.exists(): raise FileNotFoundError(f"File '{file_path}' does not exist in skill '{skill_name}'") if not full_path.is_file(): raise FileNotFoundError(f"'{file_path}' is not a file") file_size = full_path.stat().st_size if file_size > MAX_FILE_SIZE: raise FileTooBigError( f"File too large ({file_size / 1024:.1f} KB). " f"Maximum size is {MAX_FILE_SIZE / 1024:.1f} KB." ) return full_path.read_text() @staticmethod def create_file(skill_name: str, file_path: str, content: str) -> None: """ Create a new skill file. Args: skill_name: Name of the skill file_path: Relative path for the new file content: File content Raises: SkillNotFoundError: If skill doesn't exist InvalidPathError: If path is invalid FileNotFoundError: If file already exists """ # Check if skill exists first skill_dir = SKILLS_DIR / skill_name if not skill_dir.exists(): raise SkillNotFoundError(f"Skill '{skill_name}' does not exist") if not skill_dir.is_dir(): raise SkillNotFoundError(f"'{skill_name}' is not a directory") full_path = validate_path(skill_name, file_path) if full_path.exists(): raise FileNotFoundError( f"File '{file_path}' already exists in skill '{skill_name}'. " "Use update to modify it." ) # Create parent directories if needed full_path.parent.mkdir(parents=True, exist_ok=True) # Write content full_path.write_text(content) @staticmethod def update_file(skill_name: str, file_path: str, content: str) -> None: """ Update an existing skill file. Args: skill_name: Name of the skill file_path: Relative path to the file content: New file content Raises: SkillNotFoundError: If skill doesn't exist InvalidPathError: If path is invalid FileNotFoundError: If file doesn't exist """ # Check if skill exists first skill_dir = SKILLS_DIR / skill_name if not skill_dir.exists(): raise SkillNotFoundError(f"Skill '{skill_name}' does not exist") if not skill_dir.is_dir(): raise SkillNotFoundError(f"'{skill_name}' is not a directory") full_path = validate_path(skill_name, file_path) if not full_path.exists(): raise FileNotFoundError( f"File '{file_path}' does not exist in skill '{skill_name}'. " "Use create to create it." ) if not full_path.is_file(): raise FileNotFoundError(f"'{file_path}' is not a file") full_path.write_text(content) @staticmethod def delete_file(skill_name: str, file_path: str) -> None: """ Delete a skill file. Args: skill_name: Name of the skill file_path: Relative path to the file Raises: SkillNotFoundError: If skill doesn't exist InvalidPathError: If path is invalid FileNotFoundError: If file doesn't exist ProtectedFileError: If attempting to delete a protected file (SKILL.md) """ # Prevent deletion of SKILL.md if file_path == SKILL_METADATA_FILE or file_path.endswith(f"/{SKILL_METADATA_FILE}"): raise ProtectedFileError( f"Cannot delete '{SKILL_METADATA_FILE}'. This file is protected and required for skill metadata." ) # Check if skill exists first skill_dir = SKILLS_DIR / skill_name if not skill_dir.exists(): raise SkillNotFoundError(f"Skill '{skill_name}' does not exist") if not skill_dir.is_dir(): raise SkillNotFoundError(f"'{skill_name}' is not a directory") full_path = validate_path(skill_name, file_path) if not full_path.exists(): raise FileNotFoundError(f"File '{file_path}' does not exist in skill '{skill_name}'") if not full_path.is_file(): raise FileNotFoundError(f"'{file_path}' is not a file. Cannot delete directories.") full_path.unlink()

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/fkesheh/skill-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server