skill_files_crud
Perform CRUD operations on skill files to read, create, update, or delete content within skill directories, supporting both single and bulk file management.
Instructions
Unified CRUD tool for skill file operations. Supports both single and bulk operations.
IMPORTANT PATH NOTES:
All file paths are RELATIVE to the skill directory (e.g., 'main.py', 'scripts/utils.py')
NEVER use absolute paths (e.g., NOT '/Users/username/.skill-mcp/skills/my-skill/main.py')
To execute scripts, use the 'run_skill_script' tool, NOT external bash/shell tools
Operations:
read: Read a file's content
create: Create one or more files (supports atomic mode for bulk)
update: Update one or more files
delete: Delete a file (SKILL.md is protected and cannot be deleted)
Single File Examples:
Bulk File Examples:
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operation | Yes | Operation to perform: 'read', 'create', 'update', 'delete' | |
| skill_name | Yes | Name of the skill | |
| file_path | No | Relative path to file (for single file operations) | |
| content | No | File content (for single create/update) | |
| files | No | List of files for bulk create/update operations | |
| file_paths | No | List of file paths for bulk read operations | |
| atomic | No | Atomic mode: rollback all on error (for bulk create) |
Implementation Reference
- Primary handler method `skill_files_crud` that dispatches CRUD operations (read, create, update, delete) based on input.operation and handles errors.async def skill_files_crud(input_data: SkillFilesCrudInput) -> list[types.TextContent]: """Handle file CRUD operations.""" operation = input_data.operation try: if operation == "read": return await SkillFilesCrud._handle_read(input_data) elif operation == "create": return await SkillFilesCrud._handle_create(input_data) elif operation == "update": return await SkillFilesCrud._handle_update(input_data) elif operation == "delete": return await SkillFilesCrud._handle_delete(input_data) else: return [ types.TextContent( type="text", text=f"Unknown operation: {operation}. Valid operations: read, create, update, delete", ) ] except Exception as e: return [types.TextContent(type="text", text=f"Error: {str(e)}")]
- src/skill_mcp/models_crud.py:42-66 (schema)Pydantic `BaseModel` defining the input schema for the `skill_files_crud` tool, including fields for operation, skill_name, single/bulk file paths, content, and atomic flag.class SkillFilesCrudInput(BaseModel): """Unified input for skill file CRUD operations.""" operation: str = Field(description="Operation to perform: 'read', 'create', 'update', 'delete'") skill_name: str = Field(description="Name of the skill") # Single file operations file_path: Optional[str] = Field( default=None, description="Relative path to file (for single file operations)" ) content: Optional[str] = Field( default=None, description="File content (for single create/update)" ) # Bulk file operations files: Optional[List[FileSpec]] = Field( default=None, description="List of files for bulk create/update operations" ) file_paths: Optional[List[str]] = Field( default=None, description="List of file paths for bulk read operations" ) atomic: bool = Field( default=True, description="Atomic mode: rollback all on error (for bulk create)" )
- src/skill_mcp/tools/skill_files_crud.py:12-80 (registration)`get_tool_definition()` method returning the `mcp.types.Tool` object for 'skill_files_crud' with name, detailed description, and inputSchema from `SkillFilesCrudInput.model_json_schema()`.@staticmethod def get_tool_definition() -> list[types.Tool]: """Get tool definition.""" return [ types.Tool( name="skill_files_crud", description="""Unified CRUD tool for skill file operations. Supports both single and bulk operations. IMPORTANT PATH NOTES: - All file paths are RELATIVE to the skill directory (e.g., 'main.py', 'scripts/utils.py') - NEVER use absolute paths (e.g., NOT '/Users/username/.skill-mcp/skills/my-skill/main.py') - To execute scripts, use the 'run_skill_script' tool, NOT external bash/shell tools **Operations:** - **read**: Read a file's content - **create**: Create one or more files (supports atomic mode for bulk) - **update**: Update one or more files - **delete**: Delete a file (SKILL.md is protected and cannot be deleted) **Single File Examples:** ```json // Read a file {"operation": "read", "skill_name": "my-skill", "file_path": "script.py"} // Create a single file {"operation": "create", "skill_name": "my-skill", "file_path": "new.py", "content": "print('hello')"} // Update a single file {"operation": "update", "skill_name": "my-skill", "file_path": "script.py", "content": "print('updated')"} // Delete a file {"operation": "delete", "skill_name": "my-skill", "file_path": "old.py"} ``` **Bulk File Examples:** ```json // Read multiple files { "operation": "read", "skill_name": "my-skill", "file_paths": ["file1.py", "file2.py", "file3.py"] } // Create multiple files atomically (all-or-nothing) { "operation": "create", "skill_name": "my-skill", "files": [ {"path": "src/main.py", "content": "# Main"}, {"path": "src/utils.py", "content": "# Utils"}, {"path": "README.md", "content": "# Docs"} ], "atomic": true } // Update multiple files { "operation": "update", "skill_name": "my-skill", "files": [ {"path": "file1.py", "content": "new content 1"}, {"path": "file2.py", "content": "new content 2"} ] } ```""", inputSchema=SkillFilesCrudInput.model_json_schema(), ) ]
- src/skill_mcp/server.py:30-38 (registration)MCP server `list_tools()` handler that extends the tools list with `SkillFilesCrud.get_tool_definition()`, registering the tool.@app.list_tools() # type: ignore[misc] async def list_tools() -> list[types.Tool]: """List available tools.""" tools = [] tools.extend(SkillCrud.get_tool_definition()) tools.extend(SkillFilesCrud.get_tool_definition()) tools.extend(SkillEnvCrud.get_tool_definition()) tools.extend(ScriptTools.get_script_tools()) return tools
- src/skill_mcp/server.py:49-51 (handler)Dispatch branch in top-level `@app.call_tool()` handler that parses arguments into `SkillFilesCrudInput` and invokes `SkillFilesCrud.skill_files_crud()`.elif name == "skill_files_crud": files_input = SkillFilesCrudInput(**arguments) return await SkillFilesCrud.skill_files_crud(files_input)