a519798e69
Removed BUILTIN_TOKEN (dev) and the hardcoded prod/nautilus tokens from BUILTIN_SERVERS. install.sh now refuses to run if GITEA_DEFAULT_TOKEN, GITEA_PROD_TOKEN, or GITEA_NAUTILUS_TOKEN env vars are missing. Why: discovered during the LegalCrm 2026-04-25 security audit. Per the Infisical-only secrets policy, tokens MUST come from Infisical (/gitea per-environment → API_TOKEN), never baked into source. The script was previously a public credential dump for all three production Gitea instances. Run with the env vars set before re-installing: GITEA_DEFAULT_TOKEN=<dev> GITEA_PROD_TOKEN=<prod> GITEA_NAUTILUS_TOKEN=<nautilus> ./install.sh Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
488 lines
17 KiB
Bash
Executable File
488 lines
17 KiB
Bash
Executable File
#!/bin/bash
|
|
# install.sh - Install/upgrade gitea-mcp and configure global MCP server
|
|
#
|
|
# Usage:
|
|
# curl -fsSL https://gitea.dev.marcus-law.co.il/mcp-servers/gitea-mcp/raw/branch/main/install.sh | bash
|
|
# # or locally:
|
|
# bash install.sh
|
|
#
|
|
# Options (via env vars):
|
|
# GITEA_MCP_DIR=~/custom-dir # Custom install directory (default: ~/.gitea-mcp)
|
|
# GITEA_MCP_BRANCH=dev # Custom branch (default: main)
|
|
# GITEA_DEFAULT_HOST=https://... # Default Gitea host
|
|
# GITEA_DEFAULT_TOKEN=xxx # Default Gitea token
|
|
# AUTO_YES=1 # Skip all prompts
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_URL="https://gitea.dev.marcus-law.co.il/mcp-servers/gitea-mcp.git"
|
|
INSTALL_DIR="${GITEA_MCP_DIR:-$HOME/.gitea-mcp}"
|
|
BRANCH="${GITEA_MCP_BRANCH:-main}"
|
|
AUTO_YES="${AUTO_YES:-1}"
|
|
|
|
MCP_NAME="gitea-dev"
|
|
BINARY_NAME="gitea-mcp"
|
|
GOBIN="${GOPATH:-$HOME/go}/bin"
|
|
BINARY_PATH="$GOBIN/$BINARY_NAME"
|
|
|
|
CLAUDE_JSON="$HOME/.claude.json"
|
|
CLAUDE_SETTINGS="$HOME/.claude/settings.json"
|
|
|
|
# ── Helpers ─────────────────────────────────────────────────────────────────
|
|
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
|
info() { echo -e "${CYAN}>>>${NC} $*"; }
|
|
ok() { echo -e "${GREEN} ✓${NC} $*"; }
|
|
warn() { echo -e "${YELLOW} !${NC} $*"; }
|
|
error() { echo -e "${RED} ✗${NC} $*" >&2; }
|
|
|
|
ask_yes_no() {
|
|
local prompt="$1"
|
|
if [ "$AUTO_YES" = "1" ]; then return 0; fi
|
|
if [ -e /dev/tty ]; then
|
|
printf "%s [Y/n] " "$prompt"
|
|
local answer=""
|
|
read -r answer < /dev/tty 2>/dev/null || answer="y"
|
|
case "$answer" in [nN]*) return 1 ;; *) return 0 ;; esac
|
|
else
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
ask_input() {
|
|
local prompt="$1" var_name="$2" default="${3:-}"
|
|
if [ -e /dev/tty ]; then
|
|
if [ -n "$default" ]; then
|
|
printf "%s [%s]: " "$prompt" "$default"
|
|
else
|
|
printf "%s: " "$prompt"
|
|
fi
|
|
local answer=""
|
|
read -r answer < /dev/tty 2>/dev/null || answer=""
|
|
if [ -z "$answer" ]; then answer="$default"; fi
|
|
eval "$var_name=\$answer"
|
|
else
|
|
eval "$var_name=\$default"
|
|
fi
|
|
}
|
|
|
|
# ── Auto-install helpers ───────────────────────────────────────────────────
|
|
|
|
detect_pkg_manager() {
|
|
if command -v apt-get &>/dev/null; then echo "apt"
|
|
elif command -v dnf &>/dev/null; then echo "dnf"
|
|
elif command -v yum &>/dev/null; then echo "yum"
|
|
elif command -v pacman &>/dev/null; then echo "pacman"
|
|
elif command -v apk &>/dev/null; then echo "apk"
|
|
elif command -v brew &>/dev/null; then echo "brew"
|
|
else echo ""; fi
|
|
}
|
|
|
|
install_pkg() {
|
|
local pkg="$1"
|
|
local pm
|
|
pm=$(detect_pkg_manager)
|
|
|
|
case "$pm" in
|
|
apt) sudo apt-get update -qq && sudo apt-get install -y -qq "$pkg" ;;
|
|
dnf) sudo dnf install -y -q "$pkg" ;;
|
|
yum) sudo yum install -y -q "$pkg" ;;
|
|
pacman) sudo pacman -S --noconfirm "$pkg" ;;
|
|
apk) sudo apk add --quiet "$pkg" ;;
|
|
brew) brew install "$pkg" ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
install_go() {
|
|
local GO_VERSION_TARGET="1.24.2"
|
|
local ARCH
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64) ARCH="amd64" ;;
|
|
aarch64|arm64) ARCH="arm64" ;;
|
|
*) error "Unsupported architecture: $ARCH"; return 1 ;;
|
|
esac
|
|
local OS
|
|
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
|
|
local TARBALL="go${GO_VERSION_TARGET}.${OS}-${ARCH}.tar.gz"
|
|
local URL="https://go.dev/dl/$TARBALL"
|
|
|
|
info "Downloading Go $GO_VERSION_TARGET for $OS/$ARCH ..."
|
|
local tmpfile
|
|
tmpfile=$(mktemp)
|
|
if command -v curl &>/dev/null; then
|
|
curl -fsSL "$URL" -o "$tmpfile"
|
|
elif command -v wget &>/dev/null; then
|
|
wget -q "$URL" -O "$tmpfile"
|
|
else
|
|
error "Neither curl nor wget found — cannot download Go"
|
|
return 1
|
|
fi
|
|
|
|
info "Installing Go to /usr/local/go ..."
|
|
sudo rm -rf /usr/local/go
|
|
sudo tar -C /usr/local -xzf "$tmpfile"
|
|
rm -f "$tmpfile"
|
|
|
|
# Add to PATH for this session
|
|
export PATH="/usr/local/go/bin:$PATH"
|
|
|
|
# Persist in shell profile if not already there
|
|
local profile="$HOME/.profile"
|
|
[ -f "$HOME/.bashrc" ] && profile="$HOME/.bashrc"
|
|
[ -f "$HOME/.zshrc" ] && profile="$HOME/.zshrc"
|
|
if ! grep -q '/usr/local/go/bin' "$profile" 2>/dev/null; then
|
|
echo 'export PATH="/usr/local/go/bin:$PATH"' >> "$profile"
|
|
info "Added Go to PATH in $profile"
|
|
fi
|
|
|
|
ok "Go $GO_VERSION_TARGET installed"
|
|
}
|
|
|
|
# ── Step 0: Prerequisites ──────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e "${CYAN}=== Gitea MCP Server Installer ===${NC}"
|
|
echo ""
|
|
|
|
info "Checking prerequisites..."
|
|
|
|
# --- git ---
|
|
if ! command -v git &>/dev/null; then
|
|
warn "git not found, installing..."
|
|
if ! install_pkg git; then
|
|
error "Failed to install git. Install manually and re-run."
|
|
exit 1
|
|
fi
|
|
fi
|
|
ok "git ($(git --version | cut -d' ' -f3))"
|
|
|
|
# --- jq ---
|
|
if ! command -v jq &>/dev/null; then
|
|
warn "jq not found, installing..."
|
|
if ! install_pkg jq; then
|
|
error "Failed to install jq. Install manually and re-run."
|
|
exit 1
|
|
fi
|
|
fi
|
|
ok "jq ($(jq --version 2>/dev/null))"
|
|
|
|
# --- Go ---
|
|
if ! command -v go &>/dev/null; then
|
|
warn "Go not found, installing..."
|
|
if ! install_go; then
|
|
error "Failed to install Go. Install manually from https://go.dev/dl/ and re-run."
|
|
exit 1
|
|
fi
|
|
fi
|
|
GO_VERSION=$(go version | grep -oP 'go\d+\.\d+')
|
|
GO_MAJOR=$(echo "$GO_VERSION" | grep -oP '\d+' | head -1)
|
|
GO_MINOR=$(echo "$GO_VERSION" | grep -oP '\d+' | tail -1)
|
|
if [ "$GO_MAJOR" -lt 1 ] || { [ "$GO_MAJOR" -eq 1 ] && [ "$GO_MINOR" -lt 24 ]; }; then
|
|
warn "Go $GO_VERSION is too old (need 1.24+), upgrading..."
|
|
if ! install_go; then
|
|
error "Failed to upgrade Go. Install manually from https://go.dev/dl/ and re-run."
|
|
exit 1
|
|
fi
|
|
GO_VERSION=$(go version | grep -oP 'go\d+\.\d+')
|
|
fi
|
|
ok "go ($GO_VERSION)"
|
|
|
|
# ── Step 1: Clone or update ────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
if [ -d "$INSTALL_DIR/.git" ]; then
|
|
info "Updating existing installation in $INSTALL_DIR ..."
|
|
cd "$INSTALL_DIR"
|
|
git fetch origin 2>&1 | tail -2
|
|
git reset --hard "origin/$BRANCH" 2>&1 | tail -1
|
|
ok "Updated to latest $BRANCH"
|
|
elif [ -d "$INSTALL_DIR" ]; then
|
|
# Directory exists but is not a git repo — remove and re-clone
|
|
warn "$INSTALL_DIR exists but is not a git repo, re-cloning..."
|
|
rm -rf "$INSTALL_DIR"
|
|
git clone --branch "$BRANCH" --single-branch "$REPO_URL" "$INSTALL_DIR" 2>&1 | tail -2
|
|
cd "$INSTALL_DIR"
|
|
ok "Cloned"
|
|
else
|
|
info "Cloning to $INSTALL_DIR ..."
|
|
git clone --branch "$BRANCH" --single-branch "$REPO_URL" "$INSTALL_DIR" 2>&1 | tail -2
|
|
cd "$INSTALL_DIR"
|
|
ok "Cloned"
|
|
fi
|
|
|
|
# ── Step 2: Build ──────────────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
info "Building $BINARY_NAME ..."
|
|
mkdir -p "$GOBIN"
|
|
go build -o "$BINARY_PATH" . 2>&1
|
|
VERSION=$("$BINARY_PATH" --version 2>/dev/null || echo "unknown")
|
|
ok "Built $BINARY_PATH ($VERSION)"
|
|
|
|
# ── Step 3: Find existing MCP config ───────────────────────────────────────
|
|
|
|
echo ""
|
|
info "Checking existing MCP configuration..."
|
|
|
|
# Determine where the MCP entry currently lives
|
|
MCP_CONFIG_FILE=""
|
|
EXISTING_ENTRY=""
|
|
|
|
# Check ~/.claude.json first (preferred location for global MCP servers)
|
|
if [ -f "$CLAUDE_JSON" ]; then
|
|
EXISTING_ENTRY=$(jq -r --arg name "$MCP_NAME" '.mcpServers[$name] // empty' "$CLAUDE_JSON" 2>/dev/null || true)
|
|
if [ -n "$EXISTING_ENTRY" ]; then
|
|
MCP_CONFIG_FILE="$CLAUDE_JSON"
|
|
fi
|
|
fi
|
|
|
|
# Check ~/.claude/settings.json (legacy location)
|
|
if [ -z "$EXISTING_ENTRY" ] && [ -f "$CLAUDE_SETTINGS" ]; then
|
|
EXISTING_ENTRY=$(jq -r --arg name "$MCP_NAME" '.mcpServers[$name] // empty' "$CLAUDE_SETTINGS" 2>/dev/null || true)
|
|
if [ -n "$EXISTING_ENTRY" ]; then
|
|
MCP_CONFIG_FILE="$CLAUDE_SETTINGS"
|
|
fi
|
|
fi
|
|
|
|
# Check for project-level .mcp.json files
|
|
FOUND_PROJECT_MCP=()
|
|
while IFS= read -r -d '' mcp_file; do
|
|
if jq -e --arg name "$MCP_NAME" '.mcpServers[$name] != null' "$mcp_file" &>/dev/null; then
|
|
FOUND_PROJECT_MCP+=("$mcp_file")
|
|
fi
|
|
done < <(find "$HOME" -maxdepth 3 -name ".mcp.json" \
|
|
-not -path "*/.claude/*" \
|
|
-not -path "*/.gitea-mcp/*" \
|
|
-not -path "*/node_modules/*" \
|
|
-print0 2>/dev/null || true)
|
|
|
|
# ── Step 4: Migrate / deduplicate ──────────────────────────────────────────
|
|
|
|
# If found in project-level files, migrate to global
|
|
if [ ${#FOUND_PROJECT_MCP[@]} -gt 0 ]; then
|
|
for mcp_file in "${FOUND_PROJECT_MCP[@]}"; do
|
|
warn "Found '$MCP_NAME' in project-level config: $mcp_file"
|
|
|
|
if [ -z "$EXISTING_ENTRY" ]; then
|
|
# No global config yet - migrate from project file
|
|
if ask_yes_no " Migrate to global config ($CLAUDE_JSON)?"; then
|
|
EXISTING_ENTRY=$(jq --arg name "$MCP_NAME" '.mcpServers[$name]' "$mcp_file")
|
|
MCP_CONFIG_FILE="$CLAUDE_JSON"
|
|
fi
|
|
fi
|
|
|
|
# Remove from project-level regardless
|
|
if ask_yes_no " Remove duplicate from $mcp_file?"; then
|
|
tmp=$(jq --arg name "$MCP_NAME" 'del(.mcpServers[$name])' "$mcp_file")
|
|
echo "$tmp" > "$mcp_file"
|
|
ok "Removed from $mcp_file"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# ── Step 5: Configure default server ───────────────────────────────────────
|
|
|
|
echo ""
|
|
|
|
# Extract existing values if we have a config
|
|
CURRENT_HOST=""
|
|
CURRENT_TOKEN=""
|
|
CURRENT_SERVERS=""
|
|
|
|
if [ -n "$EXISTING_ENTRY" ]; then
|
|
CURRENT_HOST=$(echo "$EXISTING_ENTRY" | jq -r '
|
|
(.args // []) | to_entries |
|
|
map(select(.value == "--host")) | first |
|
|
if . then (.key + 1) as $k | input | .[$k] else empty end
|
|
' 2>/dev/null || true)
|
|
# Simpler extraction
|
|
CURRENT_HOST=$(echo "$EXISTING_ENTRY" | jq -r '
|
|
.args as $a | ($a | index("--host")) as $i |
|
|
if $i then $a[$i + 1] else "" end
|
|
' 2>/dev/null || true)
|
|
CURRENT_TOKEN=$(echo "$EXISTING_ENTRY" | jq -r '.env.GITEA_ACCESS_TOKEN // ""' 2>/dev/null || true)
|
|
CURRENT_SERVERS=$(echo "$EXISTING_ENTRY" | jq -r '.env.GITEA_SERVERS // ""' 2>/dev/null || true)
|
|
|
|
ok "Existing config found"
|
|
echo " Default: ${CURRENT_HOST:-not set}"
|
|
if [ -n "$CURRENT_SERVERS" ] && [ "$CURRENT_SERVERS" != "" ]; then
|
|
echo "$CURRENT_SERVERS" | jq -r 'to_entries[] | " \(.key): \(.value.host)"' 2>/dev/null || true
|
|
fi
|
|
fi
|
|
|
|
# Determine default host and token (env vars > existing config; no built-in token).
|
|
# Per Infisical-only secrets policy, tokens MUST come from env vars at install time.
|
|
# Source values from Infisical /gitea (per environment) before re-running this script.
|
|
BUILTIN_HOST="https://gitea.dev.marcus-law.co.il"
|
|
|
|
DEFAULT_HOST="${GITEA_DEFAULT_HOST:-${CURRENT_HOST:-$BUILTIN_HOST}}"
|
|
DEFAULT_TOKEN="${GITEA_DEFAULT_TOKEN:-${CURRENT_TOKEN:-}}"
|
|
|
|
if [[ -z "$DEFAULT_TOKEN" ]]; then
|
|
err "No token resolved for default server. Set GITEA_DEFAULT_TOKEN env var (Infisical /gitea dev → API_TOKEN) and re-run."
|
|
exit 1
|
|
fi
|
|
|
|
ok "Default server: $DEFAULT_HOST"
|
|
|
|
# Built-in additional server hosts (no tokens — those come from env vars).
|
|
# Set GITEA_PROD_TOKEN and GITEA_NAUTILUS_TOKEN env vars (Infisical /gitea prod|nautilus → API_TOKEN).
|
|
BUILTIN_SERVERS_TEMPLATE='{"prod":{"host":"https://gitea.prod.marcus-law.co.il","token":"__PROD_TOKEN__","insecure":false},"nautilus":{"host":"https://gitea.nautilus.marcusgroup.org","token":"__NAUTILUS_TOKEN__","insecure":false}}'
|
|
|
|
if [[ -z "${GITEA_PROD_TOKEN:-}" || -z "${GITEA_NAUTILUS_TOKEN:-}" ]]; then
|
|
err "GITEA_PROD_TOKEN and GITEA_NAUTILUS_TOKEN env vars are required for the additional-servers template."
|
|
err "Source values from Infisical /gitea prod and /gitea nautilus, then re-run."
|
|
exit 1
|
|
fi
|
|
|
|
BUILTIN_SERVERS="${BUILTIN_SERVERS_TEMPLATE//__PROD_TOKEN__/$GITEA_PROD_TOKEN}"
|
|
BUILTIN_SERVERS="${BUILTIN_SERVERS//__NAUTILUS_TOKEN__/$GITEA_NAUTILUS_TOKEN}"
|
|
|
|
# ── Step 6: Add additional servers ─────────────────────────────────────────
|
|
|
|
SERVERS_JSON="${CURRENT_SERVERS:-$BUILTIN_SERVERS}"
|
|
|
|
while true; do
|
|
echo ""
|
|
if [ "$AUTO_YES" = "1" ]; then break; fi
|
|
if ! ask_yes_no "Add an additional Gitea server?"; then
|
|
break
|
|
fi
|
|
|
|
srv_name="" srv_host="" srv_token="" srv_insecure="false"
|
|
ask_input " Server name (e.g. prod, staging)" srv_name ""
|
|
if [ -z "$srv_name" ]; then break; fi
|
|
|
|
# Check if already exists
|
|
if [ -n "$SERVERS_JSON" ] && echo "$SERVERS_JSON" | jq -e --arg n "$srv_name" '.[$n]' &>/dev/null; then
|
|
existing_host=$(echo "$SERVERS_JSON" | jq -r --arg n "$srv_name" '.[$n].host')
|
|
warn "Server '$srv_name' already configured: $existing_host"
|
|
if ! ask_yes_no " Overwrite?"; then continue; fi
|
|
fi
|
|
|
|
ask_input " Host URL" srv_host ""
|
|
ask_input " Access token" srv_token ""
|
|
ask_input " Skip TLS verification? (y/n)" srv_insecure "n"
|
|
[[ "$srv_insecure" =~ ^[Yy] ]] && srv_insecure="true" || srv_insecure="false"
|
|
|
|
if [ -z "$SERVERS_JSON" ] || [ "$SERVERS_JSON" = "" ]; then
|
|
SERVERS_JSON="{}"
|
|
fi
|
|
SERVERS_JSON=$(echo "$SERVERS_JSON" | jq \
|
|
--arg n "$srv_name" --arg h "$srv_host" --arg t "$srv_token" --argjson i "$srv_insecure" \
|
|
'.[$n] = {host: $h, token: $t, insecure: $i}')
|
|
|
|
ok "Added server '$srv_name': $srv_host"
|
|
done
|
|
|
|
# ── Step 7: Write global MCP config ───────────────────────────────────────
|
|
|
|
echo ""
|
|
info "Writing global MCP configuration..."
|
|
|
|
# Build the MCP entry
|
|
if [ -n "$SERVERS_JSON" ] && [ "$SERVERS_JSON" != "{}" ] && [ "$SERVERS_JSON" != "" ]; then
|
|
MCP_ENTRY=$(jq -n \
|
|
--arg cmd "$BINARY_PATH" \
|
|
--arg host "$DEFAULT_HOST" \
|
|
--arg token "$DEFAULT_TOKEN" \
|
|
--arg servers "$SERVERS_JSON" \
|
|
'{
|
|
command: $cmd,
|
|
args: ["-t", "stdio", "--host", $host],
|
|
env: {
|
|
GITEA_ACCESS_TOKEN: $token,
|
|
GITEA_SERVERS: $servers
|
|
}
|
|
}')
|
|
else
|
|
MCP_ENTRY=$(jq -n \
|
|
--arg cmd "$BINARY_PATH" \
|
|
--arg host "$DEFAULT_HOST" \
|
|
--arg token "$DEFAULT_TOKEN" \
|
|
'{
|
|
command: $cmd,
|
|
args: ["-t", "stdio", "--host", $host],
|
|
env: {
|
|
GITEA_ACCESS_TOKEN: $token
|
|
}
|
|
}')
|
|
fi
|
|
|
|
# Write to ~/.claude.json (global MCP config location)
|
|
if [ ! -f "$CLAUDE_JSON" ]; then
|
|
echo '{}' > "$CLAUDE_JSON"
|
|
fi
|
|
|
|
tmp=$(jq --arg name "$MCP_NAME" --argjson entry "$MCP_ENTRY" \
|
|
'.mcpServers[$name] = $entry' "$CLAUDE_JSON")
|
|
echo "$tmp" > "$CLAUDE_JSON"
|
|
ok "Written to $CLAUDE_JSON"
|
|
|
|
# Clean up from settings.json if it exists there (legacy location)
|
|
if [ -f "$CLAUDE_SETTINGS" ]; then
|
|
if jq -e --arg name "$MCP_NAME" '.mcpServers[$name] != null' "$CLAUDE_SETTINGS" &>/dev/null; then
|
|
tmp=$(jq --arg name "$MCP_NAME" 'del(.mcpServers[$name])' "$CLAUDE_SETTINGS")
|
|
echo "$tmp" > "$CLAUDE_SETTINGS"
|
|
ok "Removed legacy entry from $CLAUDE_SETTINGS"
|
|
fi
|
|
fi
|
|
|
|
# ── Step 8: Clean up duplicates in other config files ──────────────────────
|
|
|
|
echo ""
|
|
info "Checking for duplicate configs..."
|
|
|
|
# Clean from project-level .mcp.json files
|
|
while IFS= read -r -d '' mcp_file; do
|
|
if jq -e --arg name "$MCP_NAME" '.mcpServers[$name] != null' "$mcp_file" &>/dev/null; then
|
|
warn "Duplicate found in $mcp_file"
|
|
if ask_yes_no " Remove '$MCP_NAME' from $mcp_file?"; then
|
|
tmp=$(jq --arg name "$MCP_NAME" 'del(.mcpServers[$name])' "$mcp_file")
|
|
echo "$tmp" > "$mcp_file"
|
|
ok "Removed"
|
|
fi
|
|
fi
|
|
done < <(find "$HOME" -maxdepth 3 -name ".mcp.json" \
|
|
-not -path "*/.claude/*" \
|
|
-not -path "*/.gitea-mcp/*" \
|
|
-not -path "*/node_modules/*" \
|
|
-print0 2>/dev/null || true)
|
|
|
|
# Clean from ~/.claude/settings.json if we wrote to ~/.claude.json
|
|
if [ -f "$CLAUDE_SETTINGS" ]; then
|
|
if jq -e --arg name "$MCP_NAME" '.mcpServers[$name] != null' "$CLAUDE_SETTINGS" &>/dev/null; then
|
|
warn "Duplicate found in $CLAUDE_SETTINGS"
|
|
if ask_yes_no " Remove from $CLAUDE_SETTINGS? (already in $CLAUDE_JSON)"; then
|
|
tmp=$(jq --arg name "$MCP_NAME" 'del(.mcpServers[$name])' "$CLAUDE_SETTINGS")
|
|
echo "$tmp" > "$CLAUDE_SETTINGS"
|
|
ok "Removed"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# ── Done ───────────────────────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e "${CYAN}=== Configured Servers ===${NC}"
|
|
echo " default: $DEFAULT_HOST"
|
|
if [ -n "$SERVERS_JSON" ] && [ "$SERVERS_JSON" != "{}" ] && [ "$SERVERS_JSON" != "" ]; then
|
|
echo "$SERVERS_JSON" | jq -r 'to_entries[] | " \(.key): \(.value.host)\(if .value.insecure then " (insecure)" else "" end)"'
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}=== Installation complete! ===${NC}"
|
|
echo ""
|
|
echo " Binary: $BINARY_PATH ($VERSION)"
|
|
echo " Config: $CLAUDE_JSON"
|
|
echo " Source: $INSTALL_DIR"
|
|
echo ""
|
|
echo "Restart Claude Code to load the new MCP server."
|
|
echo ""
|
|
echo "To upgrade later:"
|
|
echo " curl -fsSL https://gitea.dev.marcus-law.co.il/mcp-servers/gitea-mcp/raw/branch/main/install.sh | bash"
|
|
echo ""
|