#!/usr/bin/env bash # Status and one-command recovery of the temporary Cloudflare quick tunnel for the # Claude/ChatGPT MCP connector. A quick tunnel gets a NEW random address after a # restart; "refresh" writes it to .env (ZP_MCP_PUBLIC_URL, used by OAuth) and # recreates the MCP service. A stable address needs a named tunnel, Tailscale # Funnel or ngrok with a static domain instead of this quick tunnel. set -euo pipefail project_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" env_file="$project_root/.env" compose=(bash "$project_root/scripts/compose.sh" --profile claude --profile claude-tunnel) tunnel_id() { "${compose[@]}" ps -q claude-tunnel; } mcp_id() { "${compose[@]}" ps -q claude-mcp; } current_url() { local id; id="$(tunnel_id)" [[ -n "$id" ]] || return 0 docker logs "$id" 2>&1 | grep -oE 'https://[a-z0-9-]+\.trycloudflare\.com' | tail -1 } public_ok() { [[ -n "${1:-}" ]] && [[ "$(curl -s -o /dev/null -w '%{http_code}' -m 20 "$1/.well-known/oauth-authorization-server" || true)" == 200 ]] } case "${1:-status}" in status) url="$(current_url)" configured="$(grep -E '^ZP_MCP_PUBLIC_URL=' "$env_file" | cut -d= -f2- || true)" echo "Tunel: ${url:-nebeží}" echo "V .env: ${configured:-chýba}" if public_ok "$url" && [[ "$configured" == "$url/mcp" ]]; then echo "Stav: OK, link pre konektor: $url/mcp" else echo "Stav: NEFUNKČNÝ alebo nezhoduje sa s .env -> spusti: bash scripts/claude_tunnel.sh refresh" exit 1 fi ;; refresh) old="$(current_url)" "${compose[@]}" up -d --no-deps claude-tunnel >/dev/null docker restart "$(tunnel_id)" >/dev/null url="" for _ in $(seq 1 60); do url="$(current_url)" [[ -n "$url" && "$url" != "$old" ]] && break sleep 2 done [[ -n "$url" && "$url" != "$old" ]] || { echo "Nový tunel sa nepodarilo získať." >&2; exit 1; } tmp="$(mktemp "$env_file.XXXX")" grep -vE '^ZP_MCP_PUBLIC_URL=' "$env_file" > "$tmp" || true echo "ZP_MCP_PUBLIC_URL=$url/mcp" >> "$tmp" chmod 600 "$tmp"; mv "$tmp" "$env_file" "${compose[@]}" up -d --no-deps --force-recreate claude-mcp >/dev/null for _ in $(seq 1 60); do [[ "$(docker inspect -f '{{.State.Health.Status}}' "$(mcp_id)" 2>/dev/null)" == healthy ]] && break sleep 2 done for _ in $(seq 1 15); do public_ok "$url" && break; sleep 2; done public_ok "$url" || { echo "Tunel beží, ale verejná adresa ešte neodpovedá: $url" >&2; exit 1; } echo "Nový link pre konektor v Claude/ChatGPT: $url/mcp" echo "V Claude odstráň starý konektor, pridaj tento link a prihlás sa (ZP_MCP_LOGIN_PASSWORD z .env)." ;; *) echo "Použitie: bash scripts/claude_tunnel.sh {status|refresh}" >&2 exit 64 ;; esac