-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathsetup.sh
327 lines (292 loc) · 12.5 KB
/
setup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status.
# --- Helper Functions ---
info() {
echo "[INFO] $1"
}
warn() {
echo "[WARN] $1"
}
error() {
echo "[ERROR] $1" >&2
exit 1
}
# Function to check if a command exists
command_exists() {
command -v "$1" &> /dev/null
}
# --- OS Detection ---
OS="$(uname -s)"
case "$OS" in
Linux*) PLATFORM=linux;;
Darwin*) PLATFORM=macos;;
CYGWIN*|MINGW*|MSYS*) PLATFORM=windows;;
*) error "Unsupported operating system: $OS";;
esac
info "Detected platform: $PLATFORM"
# --- Dependency Installation ---
JQ_INSTALLED=false
UV_INSTALLED=false
PYTHON310_INSTALLED=false
# Check for jq
if command_exists jq; then
info "jq is already installed."
JQ_INSTALLED=true
else
info "jq not found. Attempting installation..."
case "$PLATFORM" in
linux)
if command_exists apt-get; then
sudo apt-get update && sudo apt-get install -y jq || warn "Failed to install jq using apt-get."
elif command_exists yum; then
sudo yum install -y jq || warn "Failed to install jq using yum."
elif command_exists dnf; then
sudo dnf install -y jq || warn "Failed to install jq using dnf."
elif command_exists pacman; then
sudo pacman -Syu --noconfirm jq || warn "Failed to install jq using pacman."
else
warn "Could not find apt-get, yum, dnf, or pacman. Please install jq manually."
fi
;;
macos)
if command_exists brew; then
brew install jq || warn "Failed to install jq using Homebrew."
else
warn "Homebrew not found. Please install jq manually (e.g., 'brew install jq')."
fi
;;
windows)
if command_exists pacman; then # MSYS2/Git Bash likely has pacman
pacman -S --noconfirm jq || warn "Failed to install jq using pacman."
elif command_exists choco; then
choco install jq || warn "Failed to install jq using Chocolatey."
else
warn "Could not find pacman or choco. Please install jq manually."
fi
;;
esac
# Re-check after attempting install
if command_exists jq; then
info "jq installed successfully."
JQ_INSTALLED=true
fi
fi
if [ "$JQ_INSTALLED" = false ]; then
error "jq is required but could not be installed. Please install it manually and re-run the script."
fi
# Check for uv
if command_exists uv; then
info "uv is already installed."
UV_INSTALLED=true
else
info "uv not found. Attempting installation..."
# Try pip first if available
if command_exists pip; then
pip install uv && UV_INSTALLED=true
elif command_exists pip3; then
pip3 install uv && UV_INSTALLED=true
fi
# If pip didn't work or isn't available, try curl/sh (Linux/macOS)
if [ "$UV_INSTALLED" = false ] && [ "$PLATFORM" != "windows" ]; then
if command_exists curl; then
info "Attempting uv install via curl | sh ..."
curl -LsSf https://astral.sh/uv/install.sh | sh && UV_INSTALLED=true
# Add uv to PATH for the current script session if installed this way
if [ "$UV_INSTALLED" = true ]; then
# Source the environment or update PATH - assuming install adds to $HOME/.uv/bin
UV_BIN_DIR="$HOME/.uv/bin"
if [ -d "$UV_BIN_DIR" ]; then
export PATH="$UV_BIN_DIR:$PATH"
info "Added $UV_BIN_DIR to PATH for this session."
else
warn "Expected uv installation directory $UV_BIN_DIR not found after install."
# Fallback to cargo path just in case, though less likely for uv install script
export PATH="$HOME/.cargo/bin:$PATH"
fi
if ! command_exists uv; then # Check again after modifying PATH
warn "uv installed but command not found in PATH ($PATH). You may need to restart your shell or check the installation location."
UV_INSTALLED=false # Mark as failed if not found in path
else
info "uv command found in PATH after installation."
fi
fi
else
warn "curl not found. Cannot install uv using the recommended script."
fi
fi
# If still not installed, provide guidance
if [ "$UV_INSTALLED" = false ]; then
warn "Failed to automatically install uv. Please install it manually (e.g., using pip, pipx, or cargo) and ensure it's in your PATH."
warn "See: https://github.com/astral-sh/uv"
else
# Re-check after attempting install
if command_exists uv; then
info "uv installed successfully."
UV_INSTALLED=true
else
warn "uv installation attempted, but the 'uv' command was not found in PATH."
UV_INSTALLED=false
fi
fi
fi
if [ "$UV_INSTALLED" = false ]; then
error "uv is required but could not be installed or found in PATH. Please install it manually and re-run the script."
fi
# Check for Python 3.10
PYTHON310_CMD="python3.10"
if command_exists "$PYTHON310_CMD"; then
info "Python 3.10 ($PYTHON310_CMD) is already installed."
PYTHON310_INSTALLED=true
else
info "Python 3.10 ($PYTHON310_CMD) not found. Attempting installation/check..."
case "$PLATFORM" in
macos)
if command_exists brew; then
info "Attempting to install python@3.10 using Homebrew..."
brew install python@3.10 || warn "Failed to install python@3.10 using Homebrew. It might already be installed or another issue occurred."
# Re-check after attempting install
if command_exists "$PYTHON310_CMD"; then
info "Python 3.10 ($PYTHON310_CMD) found after brew install attempt."
PYTHON310_INSTALLED=true
else
warn "Could not find $PYTHON310_CMD even after attempting brew install. Please ensure Python 3.10 is installed and accessible as '$PYTHON310_CMD'."
fi
else
warn "Homebrew not found. Please install Python 3.10 manually (e.g., 'brew install python@3.10') and ensure it's available as '$PYTHON310_CMD'."
fi
;;
*) # Linux, Windows, etc.
warn "Automatic installation of Python 3.10 is only supported via Homebrew on macOS."
warn "Please ensure Python 3.10 is installed manually and accessible as '$PYTHON310_CMD'."
# Check if it exists anyway after the warning
if command_exists "$PYTHON310_CMD"; then
info "Found $PYTHON310_CMD."
PYTHON310_INSTALLED=true
fi
;;
esac
fi
if [ "$PYTHON310_INSTALLED" = false ]; then
error "Python 3.10 ($PYTHON310_CMD) is required but could not be found or installed. Please install it manually and ensure it's in your PATH as '$PYTHON310_CMD'."
fi
# --- Path Configuration ---
# Get uv path
UV_PATH=$(command -v uv)
if [ -z "$UV_PATH" ]; then
error "Could not find uv executable path even after installation checks."
fi
info "Using uv path: $UV_PATH"
# Get script directory (absolute path)
# https://stackoverflow.com/a/246128/1319998
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
SOURCE=$(readlink "$SOURCE")
[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
SCRIPT_DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
info "Script directory: $SCRIPT_DIR"
# Construct server.py path
SERVER_PY_PATH="$SCRIPT_DIR/server.py"
if [ ! -f "$SERVER_PY_PATH" ]; then
error "server.py not found in script directory: $SCRIPT_DIR"
fi
info "Using server.py path: $SERVER_PY_PATH"
# Determine Claude config path based on OS
case "$PLATFORM" in
linux)
CLAUDE_CONFIG_DIR="$HOME/.config/Claude"
;;
macos)
CLAUDE_CONFIG_DIR="$HOME/Library/Application Support/Claude"
;;
windows)
# Assuming Git Bash/MSYS environment where $HOME maps reasonably
CLAUDE_CONFIG_DIR="$HOME/AppData/Roaming/Claude"
;;
esac
CLAUDE_CONFIG_PATH="$CLAUDE_CONFIG_DIR/claude_desktop_config.json"
info "Claude config path: $CLAUDE_CONFIG_PATH"
# --- User Input ---
read -p "Enter your LUMA_API_KEY: " LUMA_API_KEY
if [ -z "$LUMA_API_KEY" ]; then
error "LUMA_API_KEY cannot be empty."
fi
# --- JSON Modification ---
# Ensure config directory exists
mkdir -p "$CLAUDE_CONFIG_DIR" || error "Failed to create Claude config directory: $CLAUDE_CONFIG_DIR"
# Ensure config file exists, creating a valid empty JSON object if it doesn't
if [ ! -f "$CLAUDE_CONFIG_PATH" ]; then
info "Claude config file not found. Creating new file."
echo "{}" > "$CLAUDE_CONFIG_PATH" || error "Failed to create Claude config file: $CLAUDE_CONFIG_PATH"
elif ! jq empty "$CLAUDE_CONFIG_PATH" > /dev/null 2>&1; then
info "Claude config file exists but is not valid JSON. Overwriting with empty object."
echo "{}" > "$CLAUDE_CONFIG_PATH" || error "Failed to overwrite invalid Claude config file: $CLAUDE_CONFIG_PATH"
fi
info "Updating Claude configuration..."
# Use jq to add/update the mcpServers entry
jq \
--arg uv_path "$UV_PATH" \
--arg server_path "$SERVER_PY_PATH" \
--arg api_key "$LUMA_API_KEY" \
--arg python_cmd "python3.10" \
'.mcpServers."Luma API MCP" = {
command: $uv_path,
args: [
"run",
"--python", $python_cmd,
"--with", "mcp[cli]",
"--with", "aiohttp",
"mcp",
"run", $server_path
],
env: {
LUMA_API_KEY: $api_key
}
}' "$CLAUDE_CONFIG_PATH" > "$CLAUDE_CONFIG_PATH.tmp" \
&& mv "$CLAUDE_CONFIG_PATH.tmp" "$CLAUDE_CONFIG_PATH"
if [ $? -ne 0 ]; then
error "Failed to update Claude config file using jq."
# Clean up temporary file if it exists
rm -f "$CLAUDE_CONFIG_PATH.tmp"
fi
# --- Restart Claude Desktop ---
info "Attempting to restart Claude Desktop application..."
warn "Please save any unsaved work in Claude Desktop, as it will be closed forcefully."
sleep 3 # Give user a moment to read the warning
case "$PLATFORM" in
linux)
info "Attempting to kill Claude process on Linux..."
pkill -f Claude || info "Claude process not found or could not be killed."
sleep 1
info "Attempting to launch Claude on Linux..."
# Try common command names. This might fail depending on installation.
(claude &) || (Claude &) || warn "Could not automatically launch Claude. Please start it manually."
;;
macos)
info "Attempting to kill Claude process on macOS..."
killall Claude || info "Claude process not found or could not be killed."
# Allow some time for the process to terminate
sleep 2
info "Attempting to launch Claude on macOS..."
open -a Claude || warn "Could not automatically launch Claude. Please start it manually."
;;
windows)
info "Attempting to kill Claude process on Windows..."
taskkill /IM Claude.exe /F > /dev/null 2>&1 || info "Claude process not found or could not be killed."
sleep 1
info "Attempting to launch Claude on Windows..."
# Try starting via typical Program Files locations in Git Bash/MSYS
if [ -f "/c/Program Files/Claude/Claude.exe" ]; then
(start "" "/c/Program Files/Claude/Claude.exe" &) || warn "Could not automatically launch Claude from Program Files. Please start it manually."
elif [ -f "/c/Program Files (x86)/Claude/Claude.exe" ]; then
(start "" "/c/Program Files (x86)/Claude/Claude.exe" &) || warn "Could not automatically launch Claude from Program Files (x86). Please start it manually."
else
# Try starting assuming it's in PATH
(start Claude.exe &) || warn "Could not automatically launch Claude (not found in common locations or PATH). Please start it manually."
fi
;;
esac
sleep 2 # Give app time to potentially start before script exits
info "Successfully configured Luma MCP in Claude Desktop!"
info "You may need to restart the Claude Desktop application for changes to take effect."