Enhance Claude Desktop MCP Setup Script with Robust Installation and Configuration Management
- Added comprehensive error handling and validation functions - Implemented backup and upgrade/clean install workflow - Enhanced system requirements and dependency checks - Improved configuration management with secure token and URL validation - Added detailed user interaction and informative console output - Implemented flexible installation modes with existing configuration preservation
This commit is contained in:
@@ -6,77 +6,270 @@
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${BLUE}Setting up MCP Integration for Claude Desktop${NC}"
|
||||
|
||||
# Error handling function
|
||||
handle_error() {
|
||||
echo -e "${RED}Error: $1${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to compare version numbers
|
||||
version_greater_equal() {
|
||||
printf '%s\n' "$2" "$1" | sort -V -C
|
||||
}
|
||||
|
||||
# Function to backup existing configuration
|
||||
backup_config() {
|
||||
local backup_dir="$MCP_DIR/backups/$(date +%Y%m%d_%H%M%S)"
|
||||
echo -e "${BLUE}Creating backup at: $backup_dir${NC}"
|
||||
|
||||
mkdir -p "$backup_dir" || handle_error "Failed to create backup directory"
|
||||
|
||||
# Backup existing configurations if they exist
|
||||
if [ -f "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" ]; then
|
||||
cp "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" "$backup_dir/" || handle_error "Failed to backup Claude config"
|
||||
fi
|
||||
|
||||
if [ -f "$MCP_DIR/homeassistant-mcp/.env" ]; then
|
||||
cp "$MCP_DIR/homeassistant-mcp/.env" "$backup_dir/" || handle_error "Failed to backup .env file"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Backup created successfully${NC}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check for existing installation
|
||||
check_existing_installation() {
|
||||
local has_existing=false
|
||||
local config_exists=false
|
||||
local repo_exists=false
|
||||
|
||||
if [ -d "$MCP_DIR/homeassistant-mcp" ]; then
|
||||
repo_exists=true
|
||||
fi
|
||||
|
||||
if [ -f "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" ] || [ -f "$MCP_DIR/homeassistant-mcp/.env" ]; then
|
||||
config_exists=true
|
||||
fi
|
||||
|
||||
if $repo_exists || $config_exists; then
|
||||
echo -e "${YELLOW}Existing MCP installation detected${NC}"
|
||||
echo -e "Found:"
|
||||
$repo_exists && echo " - MCP repository at $MCP_DIR/homeassistant-mcp"
|
||||
[ -f "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" ] && echo " - Claude Desktop configuration"
|
||||
[ -f "$MCP_DIR/homeassistant-mcp/.env" ] && echo " - Environment configuration"
|
||||
|
||||
while true; do
|
||||
echo -e "\nPlease choose an option:"
|
||||
echo "1) Upgrade existing installation (preserves configuration)"
|
||||
echo "2) Clean reinstall (backs up and replaces configuration)"
|
||||
echo "3) Exit"
|
||||
read -p "Enter your choice (1-3): " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
echo -e "${BLUE}Upgrading existing installation...${NC}"
|
||||
backup_config
|
||||
UPGRADE_MODE=true
|
||||
break
|
||||
;;
|
||||
2)
|
||||
echo -e "${BLUE}Performing clean reinstall...${NC}"
|
||||
backup_config
|
||||
|
||||
# Remove existing installation
|
||||
if [ -d "$MCP_DIR/homeassistant-mcp" ]; then
|
||||
rm -rf "$MCP_DIR/homeassistant-mcp" || handle_error "Failed to remove existing repository"
|
||||
fi
|
||||
if [ -f "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" ]; then
|
||||
rm "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" || handle_error "Failed to remove existing Claude config"
|
||||
fi
|
||||
CLEAN_INSTALL=true
|
||||
break
|
||||
;;
|
||||
3)
|
||||
echo -e "${BLUE}Installation cancelled${NC}"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Invalid choice. Please enter 1, 2, or 3${NC}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Create MCP directory if it doesn't exist
|
||||
MCP_DIR="$HOME/.mcp"
|
||||
mkdir -p "$MCP_DIR" || handle_error "Failed to create MCP directory"
|
||||
|
||||
# Create Claude Desktop config directory (macOS specific path)
|
||||
CLAUDE_CONFIG_DIR="$HOME/Library/Application Support/Claude"
|
||||
mkdir -p "$CLAUDE_CONFIG_DIR" || handle_error "Failed to create Claude config directory"
|
||||
|
||||
# Initialize installation mode flags
|
||||
UPGRADE_MODE=false
|
||||
CLEAN_INSTALL=false
|
||||
|
||||
# Check for existing installation before proceeding
|
||||
check_existing_installation
|
||||
|
||||
# Check system requirements
|
||||
echo -e "${BLUE}Checking system requirements...${NC}"
|
||||
|
||||
# Check if Homebrew is installed
|
||||
if ! command -v brew &> /dev/null; then
|
||||
echo -e "${RED}Homebrew is not installed. Installing Homebrew...${NC}"
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
echo -e "${YELLOW}Homebrew is not installed. Installing Homebrew...${NC}"
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || handle_error "Failed to install Homebrew"
|
||||
fi
|
||||
|
||||
# Check if Node.js is installed
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo -e "${RED}Node.js is not installed. Installing via Homebrew...${NC}"
|
||||
brew install node@20
|
||||
brew link node@20
|
||||
echo -e "${YELLOW}Node.js is not installed. Installing via Homebrew...${NC}"
|
||||
brew install node@20 || handle_error "Failed to install Node.js"
|
||||
brew link node@20 || handle_error "Failed to link Node.js"
|
||||
else
|
||||
NODE_VERSION=$(node -v)
|
||||
if ! version_greater_equal "${NODE_VERSION//v/}" "20.10.0"; then
|
||||
echo -e "${RED}Node.js version must be 20.10.0 or higher. Current version: $NODE_VERSION${NC}"
|
||||
echo -e "${YELLOW}Node.js version must be 20.10.0 or higher. Current version: $NODE_VERSION${NC}"
|
||||
echo -e "${BLUE}Installing Node.js 20 via Homebrew...${NC}"
|
||||
brew install node@20
|
||||
brew link node@20
|
||||
brew install node@20 || handle_error "Failed to install Node.js"
|
||||
brew link node@20 || handle_error "Failed to link Node.js"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if npm is installed
|
||||
if ! command -v npm &> /dev/null; then
|
||||
echo -e "${RED}npm is not installed. Please install npm and try again.${NC}"
|
||||
exit 1
|
||||
handle_error "npm is not installed. Please install npm and try again."
|
||||
fi
|
||||
|
||||
# Check if jq is installed
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo -e "${RED}jq is not installed. Installing via Homebrew...${NC}"
|
||||
brew install jq
|
||||
echo -e "${YELLOW}jq is not installed. Installing via Homebrew...${NC}"
|
||||
brew install jq || handle_error "Failed to install jq"
|
||||
fi
|
||||
|
||||
# Create MCP directory if it doesn't exist
|
||||
MCP_DIR="$HOME/.mcp"
|
||||
mkdir -p "$MCP_DIR"
|
||||
# Check for required development tools
|
||||
echo -e "${BLUE}Checking development dependencies...${NC}"
|
||||
REQUIRED_TOOLS=("git" "curl" "typescript")
|
||||
for tool in "${REQUIRED_TOOLS[@]}"; do
|
||||
if ! command -v "$tool" &> /dev/null; then
|
||||
case $tool in
|
||||
"typescript")
|
||||
echo -e "${YELLOW}TypeScript is not installed. Installing globally...${NC}"
|
||||
npm install -g typescript || handle_error "Failed to install TypeScript"
|
||||
;;
|
||||
*)
|
||||
echo -e "${YELLOW}$tool is not installed. Installing via Homebrew...${NC}"
|
||||
brew install "$tool" || handle_error "Failed to install $tool"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
||||
# Clone the Home Assistant MCP repository
|
||||
echo -e "${BLUE}Cloning Home Assistant MCP repository...${NC}"
|
||||
git clone https://github.com/jango-blockchained/homeassistant-mcp.git "$MCP_DIR/homeassistant-mcp"
|
||||
cd "$MCP_DIR/homeassistant-mcp"
|
||||
if [ -d "$MCP_DIR/homeassistant-mcp" ] && [ "$CLEAN_INSTALL" = false ]; then
|
||||
echo -e "${YELLOW}Repository exists. Updating...${NC}"
|
||||
cd "$MCP_DIR/homeassistant-mcp" || handle_error "Failed to change directory"
|
||||
git fetch origin || handle_error "Failed to fetch updates"
|
||||
git reset --hard origin/main || handle_error "Failed to reset to main branch"
|
||||
git clean -fd || handle_error "Failed to clean repository"
|
||||
else
|
||||
if [ -d "$MCP_DIR/homeassistant-mcp" ]; then
|
||||
rm -rf "$MCP_DIR/homeassistant-mcp" || handle_error "Failed to remove existing repository"
|
||||
fi
|
||||
git clone https://github.com/jango-blockchained/homeassistant-mcp.git "$MCP_DIR/homeassistant-mcp" || handle_error "Failed to clone repository"
|
||||
cd "$MCP_DIR/homeassistant-mcp" || handle_error "Failed to change directory"
|
||||
fi
|
||||
|
||||
# Install dependencies and build
|
||||
echo -e "${BLUE}Installing dependencies and building...${NC}"
|
||||
npm install
|
||||
npm run build
|
||||
npm ci || handle_error "Failed to install npm dependencies"
|
||||
npm run build || handle_error "Failed to build project"
|
||||
|
||||
# Create Claude Desktop config directory (macOS specific path)
|
||||
CLAUDE_CONFIG_DIR="$HOME/Library/Application Support/Claude"
|
||||
mkdir -p "$CLAUDE_CONFIG_DIR"
|
||||
# If upgrading, try to reuse existing configuration
|
||||
if [ "$UPGRADE_MODE" = true ] && [ -f "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" ]; then
|
||||
echo -e "${BLUE}Reusing existing configuration...${NC}"
|
||||
# Extract existing values
|
||||
if [ -f "$MCP_DIR/homeassistant-mcp/.env" ]; then
|
||||
source "$MCP_DIR/homeassistant-mcp/.env"
|
||||
HASS_HOST=${HASS_HOST:-""}
|
||||
HASS_TOKEN=${HASS_TOKEN:-""}
|
||||
HASS_SOCKET_URL=${HASS_SOCKET_URL:-""}
|
||||
fi
|
||||
|
||||
# Prompt for configurations
|
||||
echo -e "${BLUE}Please enter your configurations:${NC}"
|
||||
# If values are missing, prompt for them
|
||||
if [ -z "$HASS_HOST" ] || [ -z "$HASS_TOKEN" ]; then
|
||||
echo -e "${YELLOW}Some configuration values are missing. Please provide them:${NC}"
|
||||
# Get and validate Home Assistant URL
|
||||
while true; do
|
||||
read -p "Home Assistant URL (e.g., http://homeassistant.local:8123): " HASS_HOST
|
||||
if validate_url "$HASS_HOST"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Get and validate Home Assistant token
|
||||
while true; do
|
||||
read -p "Home Assistant Long-lived access token: " HASS_TOKEN
|
||||
if validate_token "$HASS_TOKEN"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Create WebSocket URL from HASS_HOST
|
||||
HASS_SOCKET_URL="${HASS_HOST/http/ws}/api/websocket"
|
||||
fi
|
||||
else
|
||||
# Prompt for configurations with validation
|
||||
echo -e "${BLUE}Please enter your configurations:${NC}"
|
||||
|
||||
# Function to validate URL
|
||||
validate_url() {
|
||||
if [[ ! "$1" =~ ^https?:// ]]; then
|
||||
handle_error "Invalid URL format. URL must start with http:// or https://"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to validate token
|
||||
validate_token() {
|
||||
if [[ -z "$1" ]]; then
|
||||
handle_error "Token cannot be empty"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get and validate Home Assistant URL
|
||||
while true; do
|
||||
read -p "Home Assistant URL (e.g., http://homeassistant.local:8123): " HASS_HOST
|
||||
if validate_url "$HASS_HOST"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Get and validate Home Assistant token
|
||||
while true; do
|
||||
read -p "Home Assistant Long-lived access token: " HASS_TOKEN
|
||||
if validate_token "$HASS_TOKEN"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Create WebSocket URL from HASS_HOST
|
||||
HASS_SOCKET_URL="${HASS_HOST/http/ws}/api/websocket"
|
||||
|
||||
# Create .env file for Home Assistant
|
||||
cat > "$MCP_DIR/homeassistant-mcp/.env" << EOL
|
||||
NODE_ENV=production
|
||||
HASS_HOST=$HASS_HOST
|
||||
HASS_TOKEN=$HASS_TOKEN
|
||||
HASS_SOCKET_URL=$HASS_SOCKET_URL
|
||||
PORT=3000
|
||||
DEBUG=false
|
||||
EOL
|
||||
|
||||
# Create base configuration for Home Assistant
|
||||
@@ -90,43 +283,30 @@ CONFIG_JSON='{
|
||||
"env": {
|
||||
"HASS_TOKEN": "'$HASS_TOKEN'",
|
||||
"HASS_HOST": "'$HASS_HOST'",
|
||||
"HASS_SOCKET_URL": "'$HASS_SOCKET_URL'",
|
||||
"NODE_ENV": "production",
|
||||
"PORT": "3000"
|
||||
"PORT": "3000",
|
||||
"DEBUG": "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
}'
|
||||
|
||||
# Prompt for enabling Brave Search
|
||||
read -p "Do you want to enable Brave Search integration? (y/n): " ENABLE_BRAVE_SEARCH
|
||||
|
||||
if [[ $ENABLE_BRAVE_SEARCH =~ ^[Yy]$ ]]; then
|
||||
# Install Brave Search MCP globally only if enabled
|
||||
echo -e "${BLUE}Installing Brave Search MCP...${NC}"
|
||||
npm install -g @modelcontextprotocol/server-brave-search
|
||||
|
||||
read -p "Brave Search API Key: " BRAVE_API_KEY
|
||||
|
||||
# Add Brave Search to the configuration
|
||||
CONFIG_JSON=$(echo $CONFIG_JSON | jq '.mcpServers += {
|
||||
"brave-search": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
|
||||
"env": {
|
||||
"BRAVE_API_KEY": "'$BRAVE_API_KEY'"
|
||||
}
|
||||
}
|
||||
}')
|
||||
fi
|
||||
|
||||
# Write the final configuration to file
|
||||
echo $CONFIG_JSON | jq '.' > "$CLAUDE_CONFIG_DIR/claude_desktop_config.json"
|
||||
echo $CONFIG_JSON | jq '.' > "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" || handle_error "Failed to write configuration file"
|
||||
|
||||
# Set proper permissions
|
||||
chmod 600 "$CLAUDE_CONFIG_DIR/claude_desktop_config.json"
|
||||
chmod 600 "$MCP_DIR/homeassistant-mcp/.env"
|
||||
chmod 600 "$CLAUDE_CONFIG_DIR/claude_desktop_config.json" || handle_error "Failed to set permissions on config file"
|
||||
chmod 600 "$MCP_DIR/homeassistant-mcp/.env" || handle_error "Failed to set permissions on .env file"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Installation complete!${NC}"
|
||||
if [ "$UPGRADE_MODE" = true ]; then
|
||||
echo -e "${BLUE}Upgraded existing installation${NC}"
|
||||
elif [ "$CLEAN_INSTALL" = true ]; then
|
||||
echo -e "${BLUE}Performed clean installation${NC}"
|
||||
echo -e "${YELLOW}Your previous configuration has been backed up to: $MCP_DIR/backups/$(ls -t "$MCP_DIR/backups" | head -n1)${NC}"
|
||||
fi
|
||||
echo -e "${BLUE}Configuration files created at:${NC}"
|
||||
echo " - $CLAUDE_CONFIG_DIR/claude_desktop_config.json"
|
||||
echo " - $MCP_DIR/homeassistant-mcp/.env"
|
||||
@@ -134,19 +314,16 @@ echo -e "${BLUE}To use the integration:${NC}"
|
||||
echo "1. Make sure Claude Desktop is installed from https://claude.ai/download"
|
||||
echo "2. Restart Claude Desktop"
|
||||
echo "3. Home Assistant MCP integration is now available"
|
||||
if [[ $ENABLE_BRAVE_SEARCH =~ ^[Yy]$ ]]; then
|
||||
echo "4. Brave Search MCP integration is also available"
|
||||
fi
|
||||
echo -e "${RED}Note: Keep your access tokens and API keys secure and never share them with others${NC}"
|
||||
echo -e "${YELLOW}Note: Keep your access tokens and API keys secure and never share them with others${NC}"
|
||||
|
||||
# Optional: Test the installations
|
||||
read -p "Would you like to test the installations? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo -e "${BLUE}Testing Home Assistant MCP connection...${NC}"
|
||||
node "$MCP_DIR/homeassistant-mcp/dist/index.js" test
|
||||
if [[ $ENABLE_BRAVE_SEARCH =~ ^[Yy]$ ]]; then
|
||||
echo -e "${BLUE}Testing Brave Search MCP...${NC}"
|
||||
npx @modelcontextprotocol/server-brave-search test
|
||||
if ! node "$MCP_DIR/homeassistant-mcp/dist/index.js" test; then
|
||||
echo -e "${RED}Home Assistant MCP test failed. Please check your configuration and try again.${NC}"
|
||||
else
|
||||
echo -e "${GREEN}Home Assistant MCP test successful!${NC}"
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user