Skip to main content
Glama

File Patch MCP Server

by shenning00
API.md15.6 kB
# Patch MCP Server - API Documentation Complete API reference for all tools and workflows provided by the Patch MCP Server. ## Table of Contents - [Core Patch Tools](#core-patch-tools) - [Analysis Tools](#analysis-tools) - [Backup Tools](#backup-tools) - [Error Recovery Workflows](#error-recovery-workflows) - [Security Features](#security-features) - [Error Types](#error-types) - [Return Value Semantics](#return-value-semantics) --- ## Core Patch Tools ### apply_patch Apply a unified diff patch to a file with optional dry-run mode. **Parameters:** - `file_path` (string, required): Path to the file to patch - `patch` (string, required): Unified diff patch content (supports multi-hunk patches) - `dry_run` (boolean, optional): If true, validate only without modifying file (default: false) **Returns:** ```python # Success { "success": True, "file_path": str, "applied": True, "changes": { "lines_added": int, "lines_removed": int, "hunks_applied": int }, "message": str } # Failure { "success": False, "file_path": str, "applied": False, "error": str, "error_type": str # See Error Types section } ``` **Example:** ```python from patch_mcp.tools.apply import apply_patch patch = """--- config.py +++ config.py @@ -1,3 +1,3 @@ def get_timeout(): - return 30 + return 60 """ # Test with dry run result = apply_patch("config.py", patch, dry_run=True) if result["success"]: # Apply for real result = apply_patch("config.py", patch) ``` **Multi-hunk Example:** ```python # Apply multiple changes atomically in one patch multi_hunk_patch = """--- config.py +++ config.py @@ -10,3 +10,3 @@ -timeout = 30 +timeout = 60 @@ -25,3 +25,3 @@ -retries = 3 +retries = 5 """ result = apply_patch("config.py", multi_hunk_patch) # Both changes applied atomically or neither ``` --- ### validate_patch Check if a patch can be applied to a file (read-only operation). **Parameters:** - `file_path` (string, required): Path to the file to validate against - `patch` (string, required): Unified diff patch content to validate **Returns:** ```python # Can apply (success) { "success": True, "file_path": str, "valid": True, "can_apply": True, "preview": { "lines_to_add": int, "lines_to_remove": int, "hunks": int, "affected_line_range": { "start": int, "end": int } }, "message": "Patch is valid and can be applied cleanly" } # Cannot apply (failure) { "success": False, # Note: False when can't apply "file_path": str, "valid": True, "can_apply": False, "preview": {...}, "reason": str, # Why it can't be applied "error_type": "context_mismatch", "message": "Patch is valid but cannot be applied to this file" } ``` **Example:** ```python from patch_mcp.tools.validate import validate_patch result = validate_patch("config.py", patch) if result["can_apply"]: print(f"Will add {result['preview']['lines_to_add']} lines") else: print(f"Cannot apply: {result['reason']}") ``` --- ### revert_patch Reverse a previously applied patch. **Parameters:** - `file_path` (string, required): Path to the file to revert - `patch` (string, required): The same patch that was previously applied **Returns:** ```python # Success { "success": True, "file_path": str, "reverted": True, "changes": { "lines_added": int, "lines_removed": int, "hunks_reverted": int }, "message": str } # Failure { "success": False, "file_path": str, "reverted": False, "error": str, "error_type": str } ``` **Example:** ```python from patch_mcp.tools.apply import apply_patch from patch_mcp.tools.revert import revert_patch # Apply patch apply_patch("config.py", patch) # Later, revert it result = revert_patch("config.py", patch) # File is back to original state ``` **Important:** - Must use the EXACT same patch that was applied - File must not have been modified in affected areas since patch was applied - For multi-hunk patches, all hunks are reverted atomically --- ### generate_patch Generate a unified diff patch by comparing two files. **Parameters:** - `original_file` (string, required): Path to the original/old version - `modified_file` (string, required): Path to the modified/new version - `context_lines` (integer, optional): Number of context lines (default: 3) **Returns:** ```python # Success { "success": True, "original_file": str, "modified_file": str, "patch": str, # Unified diff format "changes": { "lines_added": int, "lines_removed": int, "hunks": int }, "message": str } # Failure { "success": False, "error": str, "error_type": str } ``` **Example:** ```python from patch_mcp.tools.generate import generate_patch result = generate_patch("config_v1.py", "config_v2.py") if result["success"]: patch_content = result["patch"] print(f"Generated {result['changes']['hunks']} hunks") ``` --- ## Analysis Tools ### inspect_patch Analyze patch content without requiring any files. **Parameters:** - `patch` (string, required): Unified diff patch content **Returns:** ```python # Success { "success": True, "valid": True, "files": [ # Array of affected files (supports multi-file patches) { "source": str, "target": str, "hunks": int, "lines_added": int, "lines_removed": int } ], "summary": { "total_files": int, "total_hunks": int, "total_lines_added": int, "total_lines_removed": int }, "message": str } # Invalid patch { "success": False, "valid": False, "error": str, "error_type": "invalid_patch" } ``` **Example:** ```python from patch_mcp.tools.inspect import inspect_patch result = inspect_patch(patch_content) if result["success"]: print(f"Affects {result['summary']['total_files']} files") for file_info in result["files"]: print(f" {file_info['target']}: +{file_info['lines_added']} -{file_info['lines_removed']}") ``` --- ## Backup Tools ### backup_file Create a timestamped backup of a file. **Parameters:** - `file_path` (string, required): Path to the file to backup **Returns:** ```python # Success { "success": True, "original_file": str, "backup_file": str, # Format: {original}.backup.YYYYMMDD_HHMMSS "backup_size": int, "message": str } # Failure { "success": False, "original_file": str, "error": str, "error_type": str } ``` **Example:** ```python from patch_mcp.tools.backup import backup_file result = backup_file("config.py") if result["success"]: print(f"Backup created: {result['backup_file']}") ``` --- ### restore_backup Restore a file from a timestamped backup. **Parameters:** - `backup_file` (string, required): Path to the backup file - `target_file` (string, optional): Where to restore (auto-detected if None) - `force` (boolean, optional): Overwrite even if modified (default: false) **Returns:** ```python # Success { "success": True, "backup_file": str, "restored_to": str, "restored_size": int, "message": str } # Failure { "success": False, "backup_file": str, "error": str, "error_type": str } ``` **Example:** ```python from patch_mcp.tools.backup import restore_backup # Auto-detect target from backup filename result = restore_backup("config.py.backup.20250118_143052") # Explicit target result = restore_backup("config.py.backup.20250118_143052", target_file="config_restored.py") ``` --- ## Error Recovery Workflows The workflows module provides high-level patterns combining multiple tools. ### apply_patches_with_revert Apply multiple patches sequentially with automatic revert on failure. **Parameters:** - `file_path` (string, required): Path to the file - `patches` (list[string], required): List of patches to apply - `stop_on_failure` (boolean, optional): Stop at first failure (default: true) **Returns:** ```python { "success": bool, "file_path": str, "patches_applied": int, "patches_total": int, "failed_at": int | None, # Index of failed patch if any "message": str } ``` **Use cases:** Multi-step refactoring, dependent patches --- ### apply_patch_with_backup Apply patch with automatic backup and restore on failure. **Parameters:** - `file_path` (string, required): Path to the file - `patch` (string, required): Patch to apply - `keep_backup` (boolean, optional): Keep backup even on success (default: false) **Returns:** ```python { "success": bool, "file_path": str, "backup_file": str | None, "applied": bool, "restored": bool, "message": str } ``` **Use cases:** Critical files, experimental changes, production updates --- ### apply_patches_atomic Apply multiple patches to multiple files atomically - all succeed or all rollback. **Parameters:** - `patches` (list[tuple], required): List of (file_path, patch) pairs **Returns:** ```python { "success": bool, "patches_applied": int, "patches_total": int, "failed_at": int | None, "rollback_successful": bool | None, "message": str } ``` **Use cases:** Multi-file refactoring, coordinated changes, consistency requirements --- ### apply_patch_progressive Step-by-step validation with detailed error reporting. **Parameters:** - `file_path` (string, required): Path to the file - `patch` (string, required): Patch to apply **Returns:** ```python { "success": bool, "file_path": str, "steps": { "safety_check": {"passed": bool, "details": dict}, "validation": {"passed": bool, "details": dict}, "backup": {"passed": bool, "details": dict}, "apply": {"passed": bool, "details": dict}, "restore": {"passed": bool, "details": dict} | None }, "message": str } ``` **Use cases:** Debugging, troubleshooting, learning --- ## Security Features All file operations include comprehensive security checks: ### Security Validations 1. **Symlink Detection**: Symlinks are automatically rejected (security policy) 2. **Binary File Detection**: Binary files detected and rejected 3. **File Size Limits**: Maximum 10MB file size 4. **Disk Space Validation**: Minimum 100MB free space + 110% of file size 5. **Path Traversal Protection**: Prevents directory escaping attacks 6. **Permission Checks**: Read/write permissions validated 7. **Atomic Operations**: File replacements use atomic rename ### Configuration Constants ```python MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB MIN_FREE_SPACE = 100 * 1024 * 1024 # 100MB BINARY_CHECK_BYTES = 8192 # First 8KB checked NON_TEXT_THRESHOLD = 0.3 # 30% non-text = binary ``` ### Binary File Detection Files are considered binary if: - Contains null bytes (`\x00`) - Cannot be decoded as UTF-8 - More than 30% non-text characters --- ## Error Types The server provides 10 distinct error types for precise error handling: ### Standard Errors | Error Type | Description | |------------|-------------| | `file_not_found` | File doesn't exist | | `permission_denied` | Cannot read/write file | | `invalid_patch` | Patch format is malformed | | `context_mismatch` | Patch context doesn't match file content | | `encoding_error` | File encoding issue | | `io_error` | General I/O error | ### Security Errors | Error Type | Description | |------------|-------------| | `symlink_error` | Target is a symlink (security policy) | | `binary_file` | Target is a binary file (not supported) | | `disk_space_error` | Insufficient disk space | | `resource_limit` | File too large or operation timed out | --- ## Return Value Semantics ### Critical Semantics 1. **validate_patch success field**: - `success=True` when patch CAN be applied - `success=False` when patch CANNOT be applied (even if format is valid) - Always check both `success` and `can_apply` fields 2. **inspect_patch files field**: - Always returns `files` array (never `file` object) - Supports multi-file patches - Empty array for empty patches 3. **apply_patch with dry_run**: - `dry_run=True` never modifies the file - Returns same structure as normal apply - Useful for validation and preview 4. **revert_patch terminology**: - Uses `reverted` field (not `applied`) - Must use exact same patch that was applied - Fails if file was modified since patch application ### Consistent Return Structure All tools follow this pattern: **Success:** ```python { "success": True, "file_path": str, # Most tools # ... tool-specific fields ... "message": str } ``` **Failure:** ```python { "success": False, "file_path": str, # Most tools "error": str, "error_type": str, # One of 10 error types "message": str # Optional } ``` --- ## Example Workflows ### Safe Single Patch Application ```python from patch_mcp.tools.validate import validate_patch from patch_mcp.tools.backup import backup_file, restore_backup from patch_mcp.tools.apply import apply_patch # Step 1: Validate validation = validate_patch("config.py", patch) if not validation["can_apply"]: print(f"Cannot apply: {validation['reason']}") exit(1) # Step 2: Backup backup = backup_file("config.py") # Step 3: Apply result = apply_patch("config.py", patch) if not result["success"]: # Restore on failure restore_backup(backup["backup_file"]) ``` ### Multi-file Atomic Application ```python from patch_mcp.workflows import apply_patches_atomic patches = [ ("src/config.py", config_patch), ("src/utils.py", utils_patch), ("src/main.py", main_patch), ] result = apply_patches_atomic(patches) if result["success"]: print(f"Applied {result['patches_applied']} patches atomically") else: print(f"Failed at patch {result['failed_at']}, all rolled back") ``` ### Progressive Debugging ```python from patch_mcp.workflows import apply_patch_progressive result = apply_patch_progressive("module.py", patch) # Check each step for step_name, step_result in result["steps"].items(): if not step_result["passed"]: print(f"Failed at {step_name}: {step_result['details']}") break ``` --- ## Testing ### Coverage Statistics - **Total Tests**: 244 (all passing) - **Overall Coverage**: 83% - **Unit Tests**: 209 tests - **Integration Tests**: 35 tests ### Coverage Breakdown | Module | Coverage | |--------|----------| | models.py | 100% | | inspect.py | 99% | | validate.py | 92% | | revert.py | 91% | | utils.py | 88% | | apply.py | 87% | | server.py | 86% | | generate.py | 81% | | backup.py | 70% | | workflows.py | 70% | ### Running Tests ```bash # Run all tests with coverage pytest tests/ -v --cov=src/patch_mcp --cov-report=term --cov-report=html # Run specific test suites pytest tests/test_apply.py -v pytest tests/integration/test_workflows.py -v # View coverage report open htmlcov/index.html ``` --- ## Code Quality The project maintains strict code quality standards: ```bash # Format code black src/patch_mcp tests/ # Lint code ruff check src/patch_mcp tests/ # Type check mypy src/patch_mcp --strict ``` All code passes: - Black formatting (line length: 100) - Ruff linting (E, F, I, N, W rules) - Mypy strict type checking --- For workflow pattern details, see [WORKFLOWS.md](../WORKFLOWS.md). For security policy, see [SECURITY.md](../SECURITY.md). For contributing guidelines, see [CONTRIBUTING.md](../CONTRIBUTING.md).

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/shenning00/patch_mcp'

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