Add interactive setup wizard
- setup.py detects OS, installs deps, opens browser for API key, and writes claude_desktop_config.json automatically - README: quick-install section with 3 commands at the top
This commit is contained in:
parent
b598338e3e
commit
c7d5ee2006
54
README.md
54
README.md
|
|
@ -2,49 +2,60 @@
|
||||||
|
|
||||||
Collega Claude Desktop (o qualsiasi client MCP) al portale Cauldron.
|
Collega Claude Desktop (o qualsiasi client MCP) al portale Cauldron.
|
||||||
|
|
||||||
## Prerequisiti
|
## Installazione rapida (3 comandi)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.zerotohero.it/Spaike/cauldron-mcp.git
|
||||||
|
cd cauldron-mcp
|
||||||
|
python setup.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Il wizard:
|
||||||
|
1. Installa le dipendenze automaticamente
|
||||||
|
2. Apre il browser sulla pagina API Keys del portale
|
||||||
|
3. Legge la chiave che incolli nel terminale
|
||||||
|
4. Scrive `claude_desktop_config.json` senza toccare le altre configurazioni
|
||||||
|
|
||||||
|
Poi riavvia Claude Desktop — fatto.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installazione manuale (alternativa)
|
||||||
|
|
||||||
|
### Prerequisiti
|
||||||
|
|
||||||
- Python 3.10+
|
- Python 3.10+
|
||||||
- Pip
|
- pip
|
||||||
|
|
||||||
## Installazione
|
### Dipendenze
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install mcp httpx
|
pip install mcp httpx
|
||||||
```
|
```
|
||||||
|
|
||||||
Oppure con un virtual environment (consigliato):
|
### Ottenere la API Key
|
||||||
|
|
||||||
```bash
|
Accedere al portale Cauldron → menu utente → **API Keys** → "Generate".
|
||||||
python -m venv .venv
|
|
||||||
source .venv/bin/activate # Linux/Mac
|
|
||||||
# oppure: .venv\Scripts\activate # Windows
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ottenere la propria API Key
|
|
||||||
|
|
||||||
Accedere al portale Cauldron → Profilo → API Keys → "Genera nuova chiave".
|
|
||||||
La chiave ha il formato: `cldrn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
La chiave ha il formato: `cldrn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
||||||
|
|
||||||
> La chiave viene mostrata UNA SOLA VOLTA. Conservarla in modo sicuro.
|
> La chiave viene mostrata **una sola volta**. Conservarla in modo sicuro.
|
||||||
|
|
||||||
## Configurazione Claude Desktop
|
### Configurazione Claude Desktop
|
||||||
|
|
||||||
Aprire il file di configurazione di Claude Desktop:
|
Aprire il file di configurazione:
|
||||||
|
|
||||||
- **Mac**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
- **Mac**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||||
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
||||||
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
||||||
|
|
||||||
Aggiungere (o completare) la sezione `mcpServers`:
|
Aggiungere la sezione `mcpServers`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"cauldron": {
|
"cauldron": {
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["/percorso/assoluto/al/server.py"],
|
"args": ["/percorso/assoluto/cauldron-mcp/server.py"],
|
||||||
"env": {
|
"env": {
|
||||||
"CAULDRON_API_KEY": "cldrn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"CAULDRON_API_KEY": "cldrn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
}
|
}
|
||||||
|
|
@ -53,10 +64,7 @@ Aggiungere (o completare) la sezione `mcpServers`:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Sostituire `/percorso/assoluto/al/server.py` con il path reale del file.
|
Riavviare Claude Desktop.
|
||||||
Se si usa un venv: `"command": "/percorso/.venv/bin/python"`.
|
|
||||||
|
|
||||||
Riavviare Claude Desktop per caricare la configurazione.
|
|
||||||
|
|
||||||
## Tool disponibili
|
## Tool disponibili
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Cauldron Cloud MCP — Setup wizard
|
||||||
|
Installs dependencies and writes Claude Desktop config automatically.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import webbrowser
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# ── Colours ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _supports_colour() -> bool:
|
||||||
|
return sys.stdout.isatty() and platform.system() != "Windows"
|
||||||
|
|
||||||
|
if _supports_colour():
|
||||||
|
RESET = "\033[0m"
|
||||||
|
BOLD = "\033[1m"
|
||||||
|
GREEN = "\033[32m"
|
||||||
|
YELLOW = "\033[33m"
|
||||||
|
RED = "\033[31m"
|
||||||
|
CYAN = "\033[36m"
|
||||||
|
else:
|
||||||
|
RESET = BOLD = GREEN = YELLOW = RED = CYAN = ""
|
||||||
|
|
||||||
|
def ok(msg: str) -> None: print(f"{GREEN} ✓ {RESET}{msg}")
|
||||||
|
def info(msg: str) -> None: print(f"{CYAN} → {RESET}{msg}")
|
||||||
|
def warn(msg: str) -> None: print(f"{YELLOW} ⚠ {RESET}{msg}")
|
||||||
|
def err(msg: str) -> None: print(f"{RED} ✗ {RESET}{msg}")
|
||||||
|
def bold(msg: str) -> str: return f"{BOLD}{msg}{RESET}"
|
||||||
|
|
||||||
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _python_executable() -> str:
|
||||||
|
"""Return the Python executable that is running this script."""
|
||||||
|
return sys.executable
|
||||||
|
|
||||||
|
|
||||||
|
def _config_path() -> Path:
|
||||||
|
system = platform.system()
|
||||||
|
if system == "Windows":
|
||||||
|
base = Path(os.environ.get("APPDATA", "~")).expanduser()
|
||||||
|
return base / "Claude" / "claude_desktop_config.json"
|
||||||
|
if system == "Darwin":
|
||||||
|
return Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json"
|
||||||
|
# Linux / other
|
||||||
|
xdg = os.environ.get("XDG_CONFIG_HOME", "")
|
||||||
|
base = Path(xdg) if xdg else Path.home() / ".config"
|
||||||
|
return base / "Claude" / "claude_desktop_config.json"
|
||||||
|
|
||||||
|
|
||||||
|
def _read_config(path: Path) -> dict:
|
||||||
|
if path.exists():
|
||||||
|
try:
|
||||||
|
return json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
warn("Existing config file contains invalid JSON — it will be backed up and rewritten.")
|
||||||
|
backup = path.with_suffix(".json.bak")
|
||||||
|
shutil.copy(path, backup)
|
||||||
|
info(f"Backup saved to {backup}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def _write_config(path: Path, data: dict) -> None:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def _install_deps() -> bool:
|
||||||
|
packages = ["mcp>=1.0.0", "httpx>=0.27.0"]
|
||||||
|
info("Installing Python dependencies...")
|
||||||
|
result = subprocess.run(
|
||||||
|
[_python_executable(), "-m", "pip", "install", "--quiet", *packages],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
err("pip install failed:")
|
||||||
|
print(result.stderr.strip())
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _check_deps() -> bool:
|
||||||
|
try:
|
||||||
|
import mcp # noqa: F401
|
||||||
|
import httpx # noqa: F401
|
||||||
|
return True
|
||||||
|
except ImportError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_key(key: str) -> bool:
|
||||||
|
key = key.strip()
|
||||||
|
return key.startswith("cldrn_") and len(key) >= 20
|
||||||
|
|
||||||
|
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
print()
|
||||||
|
print(bold("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))
|
||||||
|
print(bold(" Cauldron Cloud — MCP Server Setup"))
|
||||||
|
print(bold("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))
|
||||||
|
print()
|
||||||
|
|
||||||
|
# ── 1. Python version check ───────────────────────────────────────────────
|
||||||
|
if sys.version_info < (3, 10):
|
||||||
|
err(f"Python 3.10+ required (you have {platform.python_version()}).")
|
||||||
|
sys.exit(1)
|
||||||
|
ok(f"Python {platform.python_version()}")
|
||||||
|
|
||||||
|
# ── 2. Dependencies ───────────────────────────────────────────────────────
|
||||||
|
if _check_deps():
|
||||||
|
ok("Dependencies already installed (mcp, httpx)")
|
||||||
|
else:
|
||||||
|
if not _install_deps():
|
||||||
|
err("Could not install dependencies. Try manually: pip install mcp httpx")
|
||||||
|
sys.exit(1)
|
||||||
|
if not _check_deps():
|
||||||
|
err("Dependencies installed but import still fails. Check your Python environment.")
|
||||||
|
sys.exit(1)
|
||||||
|
ok("Dependencies installed (mcp, httpx)")
|
||||||
|
|
||||||
|
# ── 3. Locate server.py ───────────────────────────────────────────────────
|
||||||
|
server_py = Path(__file__).resolve().parent / "server.py"
|
||||||
|
if not server_py.exists():
|
||||||
|
err(f"server.py not found at {server_py}")
|
||||||
|
sys.exit(1)
|
||||||
|
ok(f"Server script: {server_py}")
|
||||||
|
|
||||||
|
# ── 4. Get the API key ────────────────────────────────────────────────────
|
||||||
|
print()
|
||||||
|
print(bold(" Step: Generate your API key"))
|
||||||
|
print()
|
||||||
|
print(" A browser window will open to the Cauldron portal.")
|
||||||
|
print(" Log in, click Generate , copy the key and paste it below.")
|
||||||
|
print()
|
||||||
|
input(" Press ENTER to open the browser...")
|
||||||
|
|
||||||
|
portal_url = "https://cauldron.cloud/mcpKeys"
|
||||||
|
webbrowser.open(portal_url)
|
||||||
|
info(f"Opened: {portal_url}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
api_key = ""
|
||||||
|
for attempt in range(3):
|
||||||
|
raw = input(" Paste your API key here: ").strip()
|
||||||
|
if _validate_key(raw):
|
||||||
|
api_key = raw
|
||||||
|
break
|
||||||
|
err("Key must start with cldrn_ and be at least 20 characters. Try again.")
|
||||||
|
else:
|
||||||
|
err("No valid key provided. Run setup.py again when you have a key.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
ok(f"Key accepted: {api_key[:14]}…")
|
||||||
|
|
||||||
|
# ── 5. Detect Claude Desktop config ───────────────────────────────────────
|
||||||
|
config_path = _config_path()
|
||||||
|
print()
|
||||||
|
info(f"Config file: {config_path}")
|
||||||
|
|
||||||
|
config = _read_config(config_path)
|
||||||
|
|
||||||
|
# ── 6. Merge mcpServers entry ─────────────────────────────────────────────
|
||||||
|
python_cmd = _python_executable()
|
||||||
|
|
||||||
|
mcp_entry = {
|
||||||
|
"command": python_cmd,
|
||||||
|
"args": [str(server_py)],
|
||||||
|
"env": {"CAULDRON_API_KEY": api_key},
|
||||||
|
}
|
||||||
|
|
||||||
|
if "mcpServers" not in config:
|
||||||
|
config["mcpServers"] = {}
|
||||||
|
|
||||||
|
existing = config["mcpServers"].get("cauldron")
|
||||||
|
config["mcpServers"]["cauldron"] = mcp_entry
|
||||||
|
|
||||||
|
_write_config(config_path, config)
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
ok("Updated existing cauldron entry in Claude Desktop config")
|
||||||
|
else:
|
||||||
|
ok("Added cauldron entry to Claude Desktop config")
|
||||||
|
|
||||||
|
# ── 7. Done ───────────────────────────────────────────────────────────────
|
||||||
|
print()
|
||||||
|
print(bold("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))
|
||||||
|
print(bold(" Setup complete!"))
|
||||||
|
print(bold("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))
|
||||||
|
print()
|
||||||
|
print(" Next steps:")
|
||||||
|
print(f" 1. {bold('Restart Claude Desktop')}")
|
||||||
|
print(" 2. Open a new Chat")
|
||||||
|
print(" 3. Look for the 🔌 icon — cauldron should appear in the tool list")
|
||||||
|
print()
|
||||||
|
print(" Try asking Claude:")
|
||||||
|
print(f" {CYAN}\"Show me all open Sell Side deals in the Automotive sector\"{RESET}")
|
||||||
|
print(f" {CYAN}\"Are there any incoming Requests for Help we haven't answered?\"{RESET}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue