Skip to main content
Glama

MCP Agile Flow

by smian0
migration_tool.py9.08 kB
""" MCP Configuration Migration Tool Provides functionality to migrate MCP configurations between different IDEs, with smart merging and conflict resolution capabilities. """ import json import os import shutil from typing import Dict, List, Optional, Tuple # Define IDE configuration paths IDE_PATHS = { "cursor": { "darwin": "~/.cursor/mcp.json", "linux": "~/.cursor/mcp.json", "windows": "%APPDATA%\\Cursor\\mcp.json", }, "windsurf-next": { "darwin": "~/.codeium/windsurf-next/mcp_config.json", "linux": "~/.codeium/windsurf-next/mcp_config.json", "windows": "%APPDATA%\\Codeium\\windsurf-next\\mcp_config.json", }, "windsurf": { "darwin": "~/.codeium/windsurf/mcp_config.json", "linux": "~/.codeium/windsurf/mcp_config.json", "windows": "%APPDATA%\\Codeium\\windsurf\\mcp_config.json", }, "cline": { "darwin": "~/Library/Application Support/Code - Insiders/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json", "linux": "~/.config/Code - Insiders/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json", "windows": "%APPDATA%\\Code - Insiders\\User\\globalStorage\\saoudrizwan.claude-dev\\settings\\cline_mcp_settings.json", }, "roo": { "darwin": "~/Library/Application Support/Code - Insiders/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json", "linux": "~/.config/Code - Insiders/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json", "windows": "%APPDATA%\\Code - Insiders\\User\\globalStorage\\rooveterinaryinc.roo-cline\\settings\\cline_mcp_settings.json", }, "claude-desktop": { "darwin": "~/Library/Application Support/Claude/claude_desktop_config.json", "linux": "~/.config/Claude/claude_desktop_config.json", "windows": "%APPDATA%\\Claude\\claude_desktop_config.json", }, } def get_ide_path(ide: str) -> str: """Get the configuration path for an IDE on the current platform.""" platform = ( "darwin" if os.name == "posix" and os.uname().sysname == "Darwin" else "linux" if os.name == "posix" else "windows" ) # Check for environment variable override env_var = f"MCP_{ide.upper().replace('-', '_')}_PATH" if env_var in os.environ: return os.path.expanduser(os.environ[env_var]) # Get default path for platform if ide not in IDE_PATHS: raise ValueError(f"Unknown IDE: {ide}") path = IDE_PATHS[ide][platform] # Expand environment variables and user home if platform == "windows": path = os.path.expandvars(path) return os.path.expanduser(path) def create_backup(file_path: str) -> Optional[str]: """Create a backup of a file if it exists.""" if not os.path.exists(file_path): return None backup_path = f"{file_path}.bak" shutil.copy2(file_path, backup_path) return backup_path def detect_conflicts(source_config: Dict, target_config: Dict) -> List[str]: """Detect conflicts between source and target configurations.""" conflicts = [] if "mcpServers" in source_config and "mcpServers" in target_config: source_servers = source_config["mcpServers"] target_servers = target_config["mcpServers"] # Check each server in source config for server_name, server_config in source_servers.items(): if server_name in target_servers: # Server exists in both configs, check if they're different if server_config != target_servers[server_name]: conflicts.append(server_name) return conflicts def get_conflict_details(source_config: Dict, target_config: Dict, conflicts: List[str]) -> Dict: """ Generate detailed information about each conflict. Args: source_config: Source configuration dictionary target_config: Target configuration dictionary conflicts: List of conflicting server names Returns: Dictionary mapping server names to their source and target configurations """ conflict_details = {} if "mcpServers" in source_config and "mcpServers" in target_config: source_servers = source_config["mcpServers"] target_servers = target_config["mcpServers"] for server_name in conflicts: conflict_details[server_name] = { "source": source_servers.get(server_name, {}), "target": target_servers.get(server_name, {}), } return conflict_details def merge_configurations( source_config: Dict, target_config: Dict, conflict_resolutions: Dict[str, bool] ) -> Dict: """ Merge source configuration into target configuration. Args: source_config: Source configuration dictionary target_config: Target configuration dictionary conflict_resolutions: Dictionary of server names and whether to overwrite them (True = use source, False = keep target) Returns: Merged configuration dictionary """ # Start with the target config merged = target_config.copy() # If target doesn't have mcpServers, initialize it if "mcpServers" not in merged: merged["mcpServers"] = {} # If source has mcpServers, merge them if "mcpServers" in source_config: for server_name, server_config in source_config["mcpServers"].items(): # If server exists in target and we have a conflict resolution if server_name in merged["mcpServers"] and server_name in conflict_resolutions: if conflict_resolutions[server_name]: # Use source configuration merged["mcpServers"][server_name] = server_config # If False, keep target configuration else: # No conflict or not in target, add from source merged["mcpServers"][server_name] = server_config return merged def migrate_config( from_ide: str, to_ide: str, backup: bool = True ) -> Tuple[bool, Optional[str], List[str], Dict]: """ Migrate MCP configuration from one IDE to another. Args: from_ide: Source IDE name to_ide: Target IDE name backup: Whether to create backups before modifying files Returns: Tuple of (success, error_message, conflicts, conflict_details) - success: Whether the operation completed (may be True even with conflicts) - error_message: Error message if operation failed - conflicts: List of conflicting server names - conflict_details: Dictionary of detailed conflict information """ try: # Get paths source_path = get_ide_path(from_ide) target_path = get_ide_path(to_ide) # Check if source exists if not os.path.exists(source_path): return False, f"Source configuration not found at {source_path}", [], {} # Read source configuration try: with open(source_path, "r") as f: source_config = json.load(f) except json.JSONDecodeError: return ( False, f"Invalid JSON in source configuration at {source_path}", [], {}, ) # Read target configuration if it exists target_config = {} if os.path.exists(target_path): try: with open(target_path, "r") as f: target_config = json.load(f) except json.JSONDecodeError: return ( False, f"Invalid JSON in target configuration at {target_path}", [], {}, ) # Detect conflicts conflicts = detect_conflicts(source_config, target_config) # Generate conflict details if there are conflicts conflict_details = {} if conflicts: conflict_details = get_conflict_details(source_config, target_config, conflicts) # Create backup of target if it exists and backup is requested if backup and os.path.exists(target_path): backup_path = create_backup(target_path) if not backup_path: return False, f"Failed to create backup of {target_path}", [], {} # Return if we found conflicts - user needs to resolve them if conflicts: return True, None, conflicts, conflict_details # No conflicts, perform basic merge merged_config = merge_configurations(source_config, target_config, {}) # Create target directory if it doesn't exist os.makedirs(os.path.dirname(target_path), exist_ok=True) # Write merged configuration with open(target_path, "w") as f: json.dump(merged_config, f, indent=2) return True, None, [], {} except Exception as e: return False, str(e), [], {}

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/smian0/mcp-agile-flow'

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