-
Notifications
You must be signed in to change notification settings - Fork 2
/
setup.py
145 lines (127 loc) · 4.93 KB
/
setup.py
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
#!/usr/bin/env python3
"""Setup script for MCP server data science environment."""
import json
import subprocess
import sys
from pathlib import Path
import re
import time
def run_command(cmd, check=True):
"""Run a shell command and return output."""
try:
result = subprocess.run(cmd, shell=True, check=check, capture_output=True, text=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error running command '{cmd}': {e}")
return None
def ask_permission(question):
"""Ask user for permission."""
while True:
response = input(f"{question} (y/n): ").lower()
if response in ['y', 'yes']:
return True
if response in ['n', 'no']:
return False
print("Please answer 'y' or 'n'")
def check_uv():
"""Check if uv is installed and install if needed."""
if not run_command("which uv", check=False):
if ask_permission("uv is not installed. Would you like to install it?"):
print("Installing uv...")
run_command("curl -LsSf https://astral.sh/uv/install.sh | sh")
print("uv installed successfully")
else:
sys.exit("uv is required to continue")
def setup_venv():
"""Create virtual environment if it doesn't exist."""
if not Path(".venv").exists():
if ask_permission("Virtual environment not found. Create one?"):
print("Creating virtual environment...")
run_command("uv venv")
print("Virtual environment created successfully")
else:
sys.exit("Virtual environment is required to continue")
def sync_dependencies():
"""Sync project dependencies."""
print("Syncing dependencies...")
run_command("uv sync")
print("Dependencies synced successfully")
def check_claude_desktop():
"""Check if Claude desktop app is installed."""
app_path = "/Applications/Claude.app"
if not Path(app_path).exists():
print("Claude desktop app not found.")
print("Please download and install from: https://claude.ai/download")
if not ask_permission("Continue after installing Claude?"):
sys.exit("Claude desktop app is required to continue")
def setup_claude_config():
"""Setup Claude desktop config file."""
config_path = Path("~/Library/Application Support/Claude/claude_desktop_config.json").expanduser()
config_dir = config_path.parent
if not config_dir.exists():
config_dir.mkdir(parents=True)
config = {"mcpServers": {}} if not config_path.exists() else json.loads(config_path.read_text())
return config_path, config
def build_package():
"""Build package and get wheel path."""
print("Building package...")
try:
# Use Popen for real-time and complete output capture
process = subprocess.Popen(
"uv build",
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
stdout, stderr = process.communicate() # Capture output
output = stdout + stderr # Combine both streams
print(f"Raw output: {output}") # Debug: check output
except Exception as e:
sys.exit(f"Error running build: {str(e)}")
# Check if the command was successful
if process.returncode != 0:
sys.exit(f"Build failed with error code {process.returncode}")
# Extract wheel file path from the combined output
match = re.findall(r'dist/[^\s]+\.whl', output.strip())
whl_file = match[-1] if match else None
if not whl_file:
sys.exit("Failed to find wheel file in build output")
# Convert to absolute path
path = Path(whl_file).absolute()
return str(path)
def update_config(config_path, config, wheel_path):
"""Update Claude config with MCP server settings."""
config.setdefault("mcpServers", {})
config["mcpServers"]["mcp-server-ds"] = {
"command": "uvx",
"args": ["--from", wheel_path, "mcp-server-ds"]
}
config_path.write_text(json.dumps(config, indent=2))
print(f"Updated config at {config_path}")
def restart_claude():
"""Restart Claude desktop app if running."""
if run_command("pgrep -x Claude", check=False):
if ask_permission("Claude is running. Restart it?"):
print("Restarting Claude...")
run_command("pkill -x Claude")
time.sleep(2)
run_command("open -a Claude")
print("Claude restarted successfully")
else:
print("Starting Claude...")
run_command("open -a Claude")
def main():
"""Main setup function."""
print("Starting setup...")
check_uv()
setup_venv()
sync_dependencies()
check_claude_desktop()
config_path, config = setup_claude_config()
wheel_path = build_package()
update_config(config_path, config, wheel_path)
restart_claude()
print("Setup completed successfully!")
if __name__ == "__main__":
main()