1
0
mirror of https://github.com/steipete/agent-rules.git synced 2025-12-16 12:00:09 +01:00
Files
agent-rules-mirror/global-rules/mcp-sync.sh
Peter Steinberger 495810f053 Add MCP configuration documentation and sync improvements
- Update mcp-sync-rule.md with enhanced synchronization instructions
- Improve mcp-sync.sh script functionality
- Add steipete-mcps.md documenting personal MCP server setup
2025-06-13 02:44:55 +02:00

661 lines
24 KiB
Bash
Executable File

#!/bin/bash
# MCP Server Configuration Synchronizer
# This script finds and compares MCP server configurations across different applications
# It can also switch servers between local and global configurations
# Color codes for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration file paths
CLAUDE_DESKTOP_CONFIG="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
CURSOR_CONFIG="$HOME/.cursor/mcp.json"
CLAUDE_CODE_CONFIG="$HOME/.claude.json"
WINDSURF_CONFIG="$HOME/.codeium/windsurf/mcp_config.json"
VSCODE_USER_CONFIG="$HOME/Library/Application Support/Code/User/settings.json"
# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo -e "${RED}Error: jq is not installed. Please install it with: brew install jq${NC}"
exit 1
fi
# Function to display usage
usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -h, --help Show this help message"
echo " -l, --list List all MCP servers (default)"
echo " --to-global <server> Switch a server from local to global config"
echo " --to-local <server> Switch a server from global to local config"
echo " --app <app> Specify app for switching (claude-desktop|cursor|windsurf|vscode)"
echo ""
echo "Examples:"
echo " $0 # List all servers"
echo " $0 --to-global terminator --app cursor"
echo " $0 --to-local peekaboo --app claude-desktop"
exit 0
}
# Parse command line arguments
ACTION="list"
SERVER_NAME=""
TARGET_APP=""
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
;;
-l|--list)
ACTION="list"
shift
;;
--to-global)
ACTION="to-global"
SERVER_NAME="$2"
shift 2
;;
--to-local)
ACTION="to-local"
SERVER_NAME="$2"
shift 2
;;
--app)
TARGET_APP="$2"
shift 2
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
usage
;;
esac
done
# Validate required arguments for switching actions
if [[ "$ACTION" == "to-global" || "$ACTION" == "to-local" ]]; then
if [[ -z "$SERVER_NAME" ]]; then
echo -e "${RED}Error: Server name is required for $ACTION action${NC}"
usage
fi
if [[ -z "$TARGET_APP" ]]; then
echo -e "${RED}Error: App must be specified with --app (claude-desktop or cursor)${NC}"
usage
fi
if [[ "$TARGET_APP" != "claude-desktop" && "$TARGET_APP" != "cursor" && "$TARGET_APP" != "windsurf" && "$TARGET_APP" != "vscode" ]]; then
echo -e "${RED}Error: App must be one of: 'claude-desktop', 'cursor', 'windsurf', or 'vscode'${NC}"
usage
fi
fi
echo "🔍 MCP Server Configuration Synchronizer"
echo "======================================="
echo ""
# Function to extract MCP servers from a config file
extract_servers() {
local file="$1"
local format="$2"
if [ ! -f "$file" ]; then
echo "{}"
return
fi
# For large files like Claude Code config, use a more efficient approach
if [ "$format" = "claude_code" ]; then
# Extract just the mcpServers section without loading the entire file into memory
jq -c '.mcpServers // {}' "$file" 2>/dev/null || echo "{}"
elif [ "$format" = "vscode" ]; then
# VS Code stores MCP config in user settings under "mcp.servers"
jq -r '."mcp.servers" // {}' "$file" 2>/dev/null || echo "{}"
elif [ "$format" = "vscode_legacy" ]; then
# Legacy format for older VS Code versions
jq -r '.mcp.servers // {}' "$file" 2>/dev/null || echo "{}"
else
jq -r '.mcpServers // {}' "$file" 2>/dev/null || echo "{}"
fi
}
# Function to get server names from JSON
get_server_names() {
echo "$1" | jq -r 'keys[]' 2>/dev/null | sort
}
# Function to switch server from local to global npm package
switch_to_global() {
local server_name="$1"
local app="$2"
local config_file=""
# Determine config file based on app
if [[ "$app" == "claude-desktop" ]]; then
config_file="$CLAUDE_DESKTOP_CONFIG"
elif [[ "$app" == "cursor" ]]; then
config_file="$CURSOR_CONFIG"
elif [[ "$app" == "windsurf" ]]; then
config_file="$WINDSURF_CONFIG"
else
config_file="$VSCODE_USER_CONFIG"
fi
echo -e "${BLUE}Switching '$server_name' to global configuration in $app...${NC}"
# Check if server exists
local server_exists=$(jq --arg name "$server_name" '.mcpServers | has($name)' "$config_file")
if [[ "$server_exists" != "true" ]]; then
echo -e "${RED}Error: Server '$server_name' not found in $app${NC}"
return 1
fi
# Get current configuration
local current_config=$(jq --arg name "$server_name" '.mcpServers[$name]' "$config_file")
echo "Current configuration:"
echo "$current_config" | jq .
# Common npm package mappings
local npm_package=""
case "$server_name" in
"terminator")
npm_package="@steipete/terminator-mcp@beta"
;;
"agent")
npm_package="@steipete/claude-code-mcp@latest"
;;
"automator")
npm_package="@steipete/macos-automator-mcp@latest"
;;
"conduit")
npm_package="@steipete/conduit-mcp@beta"
;;
"peekaboo")
npm_package="@steipete/peekaboo-mcp@beta"
;;
*)
echo -e "${YELLOW}Warning: Unknown server '$server_name'. Please specify the npm package name:${NC}"
read -p "NPM package name: " npm_package
if [[ -z "$npm_package" ]]; then
echo -e "${RED}Error: NPM package name is required${NC}"
return 1
fi
;;
esac
# Create new global configuration
local new_config=$(echo "$current_config" | jq --arg pkg "$npm_package" '.command = "npx" | .args = ["-y", $pkg]')
echo ""
echo "New global configuration:"
echo "$new_config" | jq .
# Confirm before applying
read -p "Apply this change? (y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
echo "Change cancelled."
return 0
fi
# Apply the change
local temp_file=$(mktemp)
jq --arg name "$server_name" --argjson config "$new_config" '.mcpServers[$name] = $config' "$config_file" > "$temp_file"
if [[ $? -eq 0 ]]; then
mv "$temp_file" "$config_file"
echo -e "${GREEN}✓ Successfully switched '$server_name' to global configuration${NC}"
else
rm "$temp_file"
echo -e "${RED}Error: Failed to update configuration${NC}"
return 1
fi
}
# Function to switch server from global to local path
switch_to_local() {
local server_name="$1"
local app="$2"
local config_file=""
# Determine config file based on app
if [[ "$app" == "claude-desktop" ]]; then
config_file="$CLAUDE_DESKTOP_CONFIG"
elif [[ "$app" == "cursor" ]]; then
config_file="$CURSOR_CONFIG"
elif [[ "$app" == "windsurf" ]]; then
config_file="$WINDSURF_CONFIG"
else
config_file="$VSCODE_USER_CONFIG"
fi
echo -e "${BLUE}Switching '$server_name' to local configuration in $app...${NC}"
# Check if server exists
local server_exists=$(jq --arg name "$server_name" '.mcpServers | has($name)' "$config_file")
if [[ "$server_exists" != "true" ]]; then
echo -e "${RED}Error: Server '$server_name' not found in $app${NC}"
return 1
fi
# Get current configuration
local current_config=$(jq --arg name "$server_name" '.mcpServers[$name]' "$config_file")
echo "Current configuration:"
echo "$current_config" | jq .
# Common local paths
local local_path=""
case "$server_name" in
"terminator")
local_path="$HOME/Projects/Terminator/dist/index.js"
;;
*)
echo -e "${YELLOW}Please specify the local path for '$server_name':${NC}"
read -p "Local path: " local_path
if [[ -z "$local_path" ]]; then
echo -e "${RED}Error: Local path is required${NC}"
return 1
fi
# Expand tilde if present
local_path="${local_path/#\~/$HOME}"
;;
esac
# Check if local path exists
if [[ ! -f "$local_path" ]]; then
echo -e "${YELLOW}Warning: Local path does not exist: $local_path${NC}"
read -p "Continue anyway? (y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
return 0
fi
fi
# Determine command based on file extension
local command="node"
if [[ "$local_path" == *.py ]]; then
command="python"
elif [[ "$local_path" == *.sh ]]; then
command="bash"
fi
# Create new local configuration
local new_config=$(echo "$current_config" | jq --arg cmd "$command" --arg path "$local_path" '.command = $cmd | .args = [$path]')
echo ""
echo "New local configuration:"
echo "$new_config" | jq .
# Confirm before applying
read -p "Apply this change? (y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
echo "Change cancelled."
return 0
fi
# Apply the change
local temp_file=$(mktemp)
jq --arg name "$server_name" --argjson config "$new_config" '.mcpServers[$name] = $config' "$config_file" > "$temp_file"
if [[ $? -eq 0 ]]; then
mv "$temp_file" "$config_file"
echo -e "${GREEN}✓ Successfully switched '$server_name' to local configuration${NC}"
else
rm "$temp_file"
echo -e "${RED}Error: Failed to update configuration${NC}"
return 1
fi
}
# Only show listing output if action is "list"
if [[ "$ACTION" == "list" ]]; then
# Check which config files exist
echo "📁 Checking configuration files:"
echo ""
if [ -f "$CLAUDE_DESKTOP_CONFIG" ]; then
echo -e "${GREEN}${NC} Claude Desktop: $CLAUDE_DESKTOP_CONFIG"
CLAUDE_DESKTOP_SERVERS=$(extract_servers "$CLAUDE_DESKTOP_CONFIG" "standard")
else
echo -e "${RED}${NC} Claude Desktop: Not found"
CLAUDE_DESKTOP_SERVERS="{}"
fi
if [ -f "$CURSOR_CONFIG" ]; then
echo -e "${GREEN}${NC} Cursor: $CURSOR_CONFIG"
CURSOR_SERVERS=$(extract_servers "$CURSOR_CONFIG" "standard")
else
echo -e "${RED}${NC} Cursor: Not found"
CURSOR_SERVERS="{}"
fi
if [ -f "$CLAUDE_CODE_CONFIG" ]; then
echo -e "${GREEN}${NC} Claude Code: $CLAUDE_CODE_CONFIG"
# Claude Code doesn't store MCP servers in its config file
echo -e " ${YELLOW}Note:${NC} Claude Code doesn't use MCP servers configuration"
CLAUDE_CODE_SERVERS="{}"
else
echo -e "${RED}${NC} Claude Code: Not found"
CLAUDE_CODE_SERVERS="{}"
fi
if [ -f "$WINDSURF_CONFIG" ]; then
echo -e "${GREEN}${NC} Windsurf: $WINDSURF_CONFIG"
WINDSURF_SERVERS=$(extract_servers "$WINDSURF_CONFIG" "standard")
else
echo -e "${RED}${NC} Windsurf: Not found"
WINDSURF_SERVERS="{}"
fi
if [ -f "$VSCODE_USER_CONFIG" ]; then
echo -e "${GREEN}${NC} VS Code (User): $VSCODE_USER_CONFIG"
VSCODE_SERVERS=$(extract_servers "$VSCODE_USER_CONFIG" "vscode")
else
echo -e "${RED}${NC} VS Code (User): Not found"
VSCODE_SERVERS="{}"
fi
echo ""
echo "📊 Server Analysis:"
echo "=================="
# Get all unique server names
ALL_SERVERS=$(echo "$CLAUDE_DESKTOP_SERVERS $CURSOR_SERVERS $CLAUDE_CODE_SERVERS $WINDSURF_SERVERS $VSCODE_SERVERS" | \
jq -s 'add | keys' | jq -r '.[]' | sort -u)
# Create arrays for tracking
declare -a COMMON_SERVERS=()
declare -a CLAUDE_DESKTOP_ONLY=()
declare -a CURSOR_ONLY=()
declare -a CLAUDE_CODE_ONLY=()
declare -a WINDSURF_ONLY=()
declare -a VSCODE_ONLY=()
# Analyze each server
for server in $ALL_SERVERS; do
in_claude_desktop=$(echo "$CLAUDE_DESKTOP_SERVERS" | jq --arg s "$server" 'has($s)')
in_cursor=$(echo "$CURSOR_SERVERS" | jq --arg s "$server" 'has($s)')
in_claude_code=$(echo "$CLAUDE_CODE_SERVERS" | jq --arg s "$server" 'has($s)')
in_windsurf=$(echo "$WINDSURF_SERVERS" | jq --arg s "$server" 'has($s)')
in_vscode=$(echo "$VSCODE_SERVERS" | jq --arg s "$server" 'has($s)')
count=0
[ "$in_claude_desktop" = "true" ] && ((count++))
[ "$in_cursor" = "true" ] && ((count++))
[ "$in_claude_code" = "true" ] && ((count++))
[ "$in_windsurf" = "true" ] && ((count++))
[ "$in_vscode" = "true" ] && ((count++))
if [ $count -ge 2 ]; then
COMMON_SERVERS+=("$server")
elif [ "$in_claude_desktop" = "true" ] && [ $count -eq 1 ]; then
CLAUDE_DESKTOP_ONLY+=("$server")
elif [ "$in_cursor" = "true" ] && [ $count -eq 1 ]; then
CURSOR_ONLY+=("$server")
elif [ "$in_claude_code" = "true" ] && [ $count -eq 1 ]; then
CLAUDE_CODE_ONLY+=("$server")
elif [ "$in_windsurf" = "true" ] && [ $count -eq 1 ]; then
WINDSURF_ONLY+=("$server")
elif [ "$in_vscode" = "true" ] && [ $count -eq 1 ]; then
VSCODE_ONLY+=("$server")
fi
done
# Display results
echo ""
echo "🤝 Common Servers (in 2+ apps):"
if [ ${#COMMON_SERVERS[@]} -eq 0 ]; then
echo " None"
else
for server in "${COMMON_SERVERS[@]}"; do
# Get package/URL info from first available config
server_info=""
for servers in "$CLAUDE_DESKTOP_SERVERS" "$CURSOR_SERVERS" "$WINDSURF_SERVERS" "$VSCODE_SERVERS"; do
config=$(echo "$servers" | jq --arg s "$server" '.[$s]' 2>/dev/null)
if [ "$config" != "null" ] && [ -n "$config" ]; then
# Extract package name or URL
if echo "$config" | jq -e '.url' >/dev/null 2>&1; then
server_info=$(echo "$config" | jq -r '.url')
elif echo "$config" | jq -e '.args' >/dev/null 2>&1; then
# Look for package name in args, skip -y flag
pkg=$(echo "$config" | jq -r '.args[]' | grep -v '^-y$' | grep -E '^@|^[a-z-]+$' | grep -v '^-' | head -1)
[ -n "$pkg" ] && server_info="$pkg"
else
server_info=$(echo "$config" | jq -r '.command' | head -1)
fi
[ -n "$server_info" ] && break
fi
done
echo -e " ${GREEN}${NC} $server ($server_info)"
# Show which apps have it
apps=""
[ "$(echo "$CLAUDE_DESKTOP_SERVERS" | jq --arg s "$server" 'has($s)')" = "true" ] && apps+="Claude Desktop, "
[ "$(echo "$CURSOR_SERVERS" | jq --arg s "$server" 'has($s)')" = "true" ] && apps+="Cursor, "
[ "$(echo "$CLAUDE_CODE_SERVERS" | jq --arg s "$server" 'has($s)')" = "true" ] && apps+="Claude Code, "
[ "$(echo "$WINDSURF_SERVERS" | jq --arg s "$server" 'has($s)')" = "true" ] && apps+="Windsurf, "
[ "$(echo "$VSCODE_SERVERS" | jq --arg s "$server" 'has($s)')" = "true" ] && apps+="VS Code, "
apps=${apps%, }
echo " In: $apps"
done
fi
echo ""
echo "📱 App-Specific Servers:"
if [ ${#CLAUDE_DESKTOP_ONLY[@]} -gt 0 ]; then
echo -e "\n ${YELLOW}Claude Desktop only:${NC}"
for server in "${CLAUDE_DESKTOP_ONLY[@]}"; do
config=$(echo "$CLAUDE_DESKTOP_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
server_info=""
if echo "$config" | jq -e '.url' >/dev/null 2>&1; then
server_info=$(echo "$config" | jq -r '.url')
elif echo "$config" | jq -e '.args' >/dev/null 2>&1; then
pkg=$(echo "$config" | jq -r '.args[]' | grep -v '^-y$' | grep -E '^@|^[a-z-]+$' | grep -v '^-' | head -1)
[ -n "$pkg" ] && server_info="$pkg"
else
server_info=$(echo "$config" | jq -r '.command' | head -1)
fi
echo "$server ($server_info)"
done
fi
if [ ${#CURSOR_ONLY[@]} -gt 0 ]; then
echo -e "\n ${YELLOW}Cursor only:${NC}"
for server in "${CURSOR_ONLY[@]}"; do
config=$(echo "$CURSOR_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
server_info=""
if echo "$config" | jq -e '.url' >/dev/null 2>&1; then
server_info=$(echo "$config" | jq -r '.url')
elif echo "$config" | jq -e '.args' >/dev/null 2>&1; then
pkg=$(echo "$config" | jq -r '.args[]' | grep -v '^-y$' | grep -E '^@|^[a-z-]+$' | grep -v '^-' | head -1)
[ -n "$pkg" ] && server_info="$pkg"
else
server_info=$(echo "$config" | jq -r '.command' | head -1)
fi
echo "$server ($server_info)"
done
fi
if [ ${#CLAUDE_CODE_ONLY[@]} -gt 0 ]; then
echo -e "\n ${YELLOW}Claude Code only:${NC}"
for server in "${CLAUDE_CODE_ONLY[@]}"; do
echo "$server"
done
fi
if [ ${#WINDSURF_ONLY[@]} -gt 0 ]; then
echo -e "\n ${YELLOW}Windsurf only:${NC}"
for server in "${WINDSURF_ONLY[@]}"; do
config=$(echo "$WINDSURF_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
server_info=""
if echo "$config" | jq -e '.url' >/dev/null 2>&1; then
server_info=$(echo "$config" | jq -r '.url')
elif echo "$config" | jq -e '.args' >/dev/null 2>&1; then
pkg=$(echo "$config" | jq -r '.args[]' | grep -v '^-y$' | grep -E '^@|^[a-z-]+$' | grep -v '^-' | head -1)
[ -n "$pkg" ] && server_info="$pkg"
else
server_info=$(echo "$config" | jq -r '.command' | head -1)
fi
echo "$server ($server_info)"
done
fi
if [ ${#VSCODE_ONLY[@]} -gt 0 ]; then
echo -e "\n ${YELLOW}VS Code only:${NC}"
for server in "${VSCODE_ONLY[@]}"; do
config=$(echo "$VSCODE_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
server_info=""
if echo "$config" | jq -e '.url' >/dev/null 2>&1; then
server_info=$(echo "$config" | jq -r '.url')
elif echo "$config" | jq -e '.args' >/dev/null 2>&1; then
pkg=$(echo "$config" | jq -r '.args[]' | grep -v '^-y$' | grep -E '^@|^[a-z-]+$' | grep -v '^-' | head -1)
[ -n "$pkg" ] && server_info="$pkg"
else
server_info=$(echo "$config" | jq -r '.command' | head -1)
fi
echo "$server ($server_info)"
done
fi
# Configuration differences for common servers
echo ""
echo "🔧 Configuration Status:"
echo "======================="
# First, show servers with matching configs
echo ""
echo "✅ Shared across all apps (matching configs):"
matching_found=false
for server in "${COMMON_SERVERS[@]}"; do
# Get configurations from each app
claude_desktop_config=$(echo "$CLAUDE_DESKTOP_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
cursor_config=$(echo "$CURSOR_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
windsurf_config=$(echo "$WINDSURF_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
vscode_config=$(echo "$VSCODE_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
# Get the command/package info for display
config_cmd=""
if [ "$claude_desktop_config" != "null" ]; then
config_cmd=$(echo "$claude_desktop_config" | jq -r 'if .args then (.args | map(select(. != "-y")) | join(" ")) else .command end' 2>/dev/null)
elif [ "$cursor_config" != "null" ]; then
config_cmd=$(echo "$cursor_config" | jq -r 'if .args then (.args | map(select(. != "-y")) | join(" ")) else .command end' 2>/dev/null)
fi
# Check if all non-null configs match
configs_match=true
first_config=""
for config in "$claude_desktop_config" "$cursor_config" "$windsurf_config" "$vscode_config"; do
if [ "$config" != "null" ]; then
if [ -z "$first_config" ]; then
first_config="$config"
elif [ "$config" != "$first_config" ]; then
configs_match=false
break
fi
fi
done
if [ "$configs_match" = true ]; then
matching_found=true
echo -e " ${GREEN}${NC} $server: $config_cmd"
fi
done
if [ "$matching_found" = false ]; then
echo " None"
fi
# Then show servers with differing configs
echo ""
echo "⚠️ Configuration differences:"
diff_found=false
for server in "${COMMON_SERVERS[@]}"; do
# Get configurations from each app
claude_desktop_config=$(echo "$CLAUDE_DESKTOP_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
cursor_config=$(echo "$CURSOR_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
windsurf_config=$(echo "$WINDSURF_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
vscode_config=$(echo "$VSCODE_SERVERS" | jq --arg s "$server" '.[$s]' 2>/dev/null)
# Check if all non-null configs match
configs_match=true
first_config=""
for config in "$claude_desktop_config" "$cursor_config" "$windsurf_config" "$vscode_config"; do
if [ "$config" != "null" ]; then
if [ -z "$first_config" ]; then
first_config="$config"
elif [ "$config" != "$first_config" ]; then
configs_match=false
break
fi
fi
done
if [ "$configs_match" = false ]; then
diff_found=true
echo ""
echo -e " ${RED}${NC} $server:"
if [ "$claude_desktop_config" != "null" ]; then
cmd=$(echo "$claude_desktop_config" | jq -r 'if .args then (.args | map(select(. != "-y")) | join(" ")) else .command end' 2>/dev/null)
echo " • Claude Desktop: $cmd"
fi
if [ "$cursor_config" != "null" ] && [ "$cursor_config" != "$claude_desktop_config" ]; then
cmd=$(echo "$cursor_config" | jq -r 'if .args then (.args | map(select(. != "-y")) | join(" ")) else .command end' 2>/dev/null)
echo " • Cursor: $cmd"
fi
if [ "$windsurf_config" != "null" ] && [ "$windsurf_config" != "$claude_desktop_config" ] && [ "$windsurf_config" != "$cursor_config" ]; then
cmd=$(echo "$windsurf_config" | jq -r 'if .args then (.args | map(select(. != "-y")) | join(" ")) else .command end' 2>/dev/null)
echo " • Windsurf: $cmd"
fi
if [ "$vscode_config" != "null" ] && [ "$vscode_config" != "$claude_desktop_config" ] && [ "$vscode_config" != "$cursor_config" ] && [ "$vscode_config" != "$windsurf_config" ]; then
cmd=$(echo "$vscode_config" | jq -r 'if .args then (.args | map(select(. != "-y")) | join(" ")) else .command end' 2>/dev/null)
echo " • VS Code: $cmd"
fi
fi
done
if [ "$diff_found" = false ]; then
echo " None"
fi
# Summary
echo ""
echo "📈 Summary:"
echo "=========="
total_servers=$(echo "$ALL_SERVERS" | wc -w | tr -d ' ')
echo "Total unique servers: $total_servers"
echo "Common servers: ${#COMMON_SERVERS[@]}"
echo "App-specific servers: $((total_servers - ${#COMMON_SERVERS[@]}))"
# Sync recommendation
echo ""
echo "💡 Sync Recommendations:"
echo "======================="
if [ ${#COMMON_SERVERS[@]} -gt 0 ]; then
echo "• Review configuration differences for common servers"
fi
total_unique=$((${#CLAUDE_DESKTOP_ONLY[@]} + ${#CURSOR_ONLY[@]} + ${#CLAUDE_CODE_ONLY[@]} + ${#WINDSURF_ONLY[@]} + ${#VSCODE_ONLY[@]}))
if [ $total_unique -gt 0 ]; then
echo "• Consider adding app-specific servers to other apps for consistency"
fi
echo ""
echo "To sync configurations manually, copy the mcpServers section between config files."
echo "Remember to adjust the format for VS Code (wrap in 'mcp.servers' instead of 'mcpServers')."
fi
# Handle switching actions
if [[ "$ACTION" == "to-global" ]]; then
switch_to_global "$SERVER_NAME" "$TARGET_APP"
elif [[ "$ACTION" == "to-local" ]]; then
switch_to_local "$SERVER_NAME" "$TARGET_APP"
fi