#!/bin/bash # # Install Hindsight MCP server for Claude Desktop # # Usage: # curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- --app claude-desktop --set HINDSIGHT_API_LLM_API_KEY=YOUR_KEY # # Options: # --app Required. Target application (currently only: claude-desktop) # --set ENV=VALUE Set environment variable (can be repeated) # # Examples: # # With OpenAI # curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- \ # --app claude-desktop \ # --set HINDSIGHT_API_LLM_API_KEY=sk-... # # # With Ollama (local LLM) # curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- \ # --app claude-desktop \ # --set HINDSIGHT_API_LLM_PROVIDER=ollama \ # --set HINDSIGHT_API_LLM_MODEL=llama3.2 # # # With custom memory instructions # curl -fsSL https://hindsight.vectorize.io/get-mcp | bash -s -- \ # --app claude-desktop \ # --set HINDSIGHT_API_LLM_API_KEY=sk-... \ # --set HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take and code you write." # set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color print_info() { echo -e "${BLUE}ℹ${NC} $1" } print_success() { echo -e "${GREEN}✓${NC} $1" } print_error() { echo -e "${RED}✗${NC} $1" exit 1 } print_warning() { echo -e "${YELLOW}⚠${NC} $1" } print_banner() { echo "" # ANSI logo echo -e " \033[38;2;9;127;184m▄\033[0m\033[48;2;8;130;178m\033[38;2;5;133;186m▄\033[0m \033[48;2;10;143;160m\033[38;2;10;143;165m▄\033[0m\033[38;2;7;140;156m▄\033[0m " echo -e " \033[38;2;8;125;192m▄\033[0m \033[38;2;3;132;191m▀\033[0m\033[38;2;2;133;192m▄\033[0m \033[38;2;3;132;180m▄\033[0m\033[38;2;1;137;184m▄\033[0m\033[38;2;3;133;174m▄\033[0m \033[38;2;3;142;176m▄\033[0m\033[38;2;4;142;169m▀\033[0m \033[38;2;10;144;164m▄\033[0m " echo -e "\033[38;2;6;121;195m▀\033[0m\033[38;2;5;128;203m▀\033[0m\033[48;2;5;124;195m\033[38;2;3;125;200m▄\033[0m\033[38;2;2;126;196m▄\033[0m\033[48;2;3;128;188m\033[38;2;1;131;196m▄\033[0m\033[48;2;0;152;219m\033[38;2;2;131;191m▄\033[0m\033[38;2;1;141;196m▀\033[0m\033[38;2;1;135;183m▀\033[0m\033[38;2;1;148;198m▀\033[0m\033[48;2;1;156;202m\033[38;2;2;135;180m▄\033[0m\033[48;2;4;134;169m\033[38;2;1;137;177m▄\033[0m\033[38;2;3;138;173m▄\033[0m\033[48;2;6;137;165m\033[38;2;2;140;170m▄\033[0m\033[38;2;7;144;169m▀\033[0m\033[38;2;7;139;158m▀\033[0m" echo -e " \033[48;2;2;128;202m\033[38;2;2;124;201m▄\033[0m\033[48;2;1;130;201m\033[38;2;0;135;212m▄\033[0m\033[38;2;2;128;196m▄\033[0m \033[48;2;2;142;204m\033[38;2;7;138;199m▄\033[0m \033[38;2;1;135;186m▄\033[0m\033[48;2;1;142;186m\033[38;2;2;144;194m▄\033[0m\033[48;2;3;138;176m\033[38;2;2;134;176m▄\033[0m " echo -e " \033[48;2;8;118;200m\033[38;2;8;121;209m▄\033[0m\033[38;2;3;121;203m▀\033[0m \033[38;2;3;122;192m▀\033[0m\033[38;2;1;138;216m▀\033[0m\033[48;2;0;138;210m\033[38;2;3;128;198m▄\033[0m\033[48;2;0;126;188m\033[38;2;2;131;198m▄\033[0m\033[48;2;0;142;205m\033[38;2;3;132;193m▄\033[0m\033[38;2;1;140;196m▀\033[0m \033[38;2;4;134;175m▀\033[0m\033[48;2;13;135;167m\033[38;2;8;136;174m▄\033[0m " echo "" echo -e " ${BLUE}HINDSIGHT MCP INSTALLER${NC}" echo "" } # Parse arguments APP="" declare -a ENV_VARS=() while [[ $# -gt 0 ]]; do case $1 in --app) APP="$2" shift 2 ;; --set) ENV_VARS+=("$2") shift 2 ;; -h|--help) echo "Usage: $0 --app --set ENV=VALUE [--set ENV2=VALUE2 ...]" echo "" echo "Options:" echo " --app Required. Target application (currently only: claude-desktop)" echo " --set ENV=VALUE Set environment variable (can be repeated)" echo "" echo "Examples:" echo " # With OpenAI" echo " $0 --app claude-desktop --set HINDSIGHT_API_LLM_API_KEY=sk-..." echo "" echo " # With Ollama (local LLM, no API key needed)" echo " $0 --app claude-desktop --set HINDSIGHT_API_LLM_PROVIDER=ollama --set HINDSIGHT_API_LLM_MODEL=llama3.2" exit 0 ;; *) print_error "Unknown option: $1. Use --help for usage." ;; esac done # Validate required arguments if [ -z "$APP" ]; then print_error "Missing required argument: --app. Use --help for usage." fi if [ "$APP" != "claude-desktop" ]; then print_error "Unsupported app: $APP. Currently only 'claude-desktop' is supported." fi # Detect OS detect_os() { case "$(uname -s)" in Darwin*) echo "macos" ;; Linux*) echo "linux" ;; MINGW*|MSYS*|CYGWIN*) echo "windows" ;; *) echo "unknown" ;; esac } OS=$(detect_os) # Get Claude Desktop config path based on OS get_claude_config_path() { case "$OS" in macos) echo "$HOME/Library/Application Support/Claude/claude_desktop_config.json" ;; linux) echo "$HOME/.config/Claude/claude_desktop_config.json" ;; windows) echo "$APPDATA/Claude/claude_desktop_config.json" ;; *) print_error "Unsupported operating system: $OS" ;; esac } # Check if uvx is installed and return its path find_uvx() { # Check if in PATH if command -v uvx &> /dev/null; then command -v uvx return 0 fi # Check common installation paths local paths=( "$HOME/.local/bin/uvx" "$HOME/.cargo/bin/uvx" "/usr/local/bin/uvx" ) for path in "${paths[@]}"; do if [ -f "$path" ]; then echo "$path" return 0 fi done return 1 } # Install uv (which includes uvx) install_uv() { print_info "Installing uv..." if [ "$OS" = "windows" ]; then powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" else curl -LsSf https://astral.sh/uv/install.sh | sh fi # Source the env to get uvx in path if [ -f "$HOME/.local/bin/env" ]; then source "$HOME/.local/bin/env" fi # Find uvx again if ! UVX_PATH=$(find_uvx); then print_error "uv installed but uvx not found. Please check your installation." fi print_success "uv installed successfully" } # Update Claude Desktop config update_claude_config() { local config_path="$1" local uvx_path="$2" shift 2 local env_vars=("$@") # Create config directory if it doesn't exist mkdir -p "$(dirname "$config_path")" # Check if jq is available (needed for both new and existing configs) if ! command -v jq &> /dev/null; then print_warning "jq not found. Installing..." if [ "$OS" = "macos" ]; then if command -v brew &> /dev/null; then brew install jq else print_error "Please install jq: brew install jq" fi elif [ "$OS" = "linux" ]; then if command -v apt-get &> /dev/null; then sudo apt-get install -y jq elif command -v yum &> /dev/null; then sudo yum install -y jq else print_error "Please install jq manually" fi fi fi # Build the env object from env_vars array local env_json="{}" for env_var in "${env_vars[@]}"; do local key="${env_var%%=*}" local value="${env_var#*=}" env_json=$(echo "$env_json" | jq --arg k "$key" --arg v "$value" '. + {($k): $v}') done # Build the hindsight server config local hindsight_config hindsight_config=$(jq -n \ --arg uvx "$uvx_path" \ --argjson env "$env_json" \ '{ "command": $uvx, "args": ["--from", "hindsight-api", "hindsight-local-mcp"], "env": $env }') # Check if config file exists and has content if [ -f "$config_path" ] && [ -s "$config_path" ]; then print_info "Updating existing Claude Desktop config..." # Backup existing config cp "$config_path" "${config_path}.backup" print_info "Backed up existing config to ${config_path}.backup" # Add or update hindsight server in existing config local new_config new_config=$(jq --argjson hs "$hindsight_config" '.mcpServers.hindsight = $hs' "$config_path") echo "$new_config" > "$config_path" else print_info "Creating new Claude Desktop config..." # Create new config with hindsight server local new_config new_config=$(jq -n --argjson hs "$hindsight_config" '{"mcpServers": {"hindsight": $hs}}') echo "$new_config" > "$config_path" fi print_success "Claude Desktop config updated: $config_path" } # Main installation flow main() { print_banner print_info "App: $APP" if [ ${#ENV_VARS[@]} -gt 0 ]; then print_info "Environment variables: ${#ENV_VARS[@]} configured" fi echo "" # Step 1: Check/Install uvx print_info "Checking for uvx..." if UVX_PATH=$(find_uvx); then print_success "uvx found at: $UVX_PATH" else print_warning "uvx not found. Installing uv..." install_uv UVX_PATH=$(find_uvx) fi # Step 2: Update Claude Desktop config CONFIG_PATH=$(get_claude_config_path) print_info "Configuring Claude Desktop..." update_claude_config "$CONFIG_PATH" "$UVX_PATH" "${ENV_VARS[@]}" # Done! echo "" print_success "Installation complete!" echo "" print_info "Next steps:" echo " 1. Restart Claude Desktop" echo " 2. Look for the 'hindsight' tools (retain, recall) in Claude" echo "" } main "$@"