Created
February 5, 2026 20:25
-
-
Save Loschcode/7922910a55a05046cfe9f109fb70d023 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Linkbreakers MCP setup helper. Feel free to copy/share (e.g., as a GitHub Gist). | |
| set -euo pipefail | |
| if ! command -v python3 >/dev/null 2>&1; then | |
| echo "Error: python3 is required to update the JSON config." | |
| exit 1 | |
| fi | |
| if [ -t 1 ]; then | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[0;33m' | |
| BLUE='\033[0;34m' | |
| PURPLE='\033[0;35m' | |
| CYAN='\033[0;36m' | |
| BOLD='\033[1m' | |
| RESET='\033[0m' | |
| else | |
| RED='' | |
| GREEN='' | |
| YELLOW='' | |
| BLUE='' | |
| PURPLE='' | |
| CYAN='' | |
| BOLD='' | |
| RESET='' | |
| fi | |
| printf "${BOLD}${CYAN}Linkbreakers MCP Setup${RESET}\n" | |
| printf "${BLUE}Configure an MCP client (Claude Desktop, Continue, or any MCP-compatible client)${RESET}\n\n" | |
| INPUT="/dev/stdin" | |
| if [ ! -t 0 ]; then | |
| if [ -r /dev/tty ]; then | |
| INPUT="/dev/tty" | |
| else | |
| echo "Error: no interactive TTY available for prompts." | |
| echo "Hint: run this script directly or with bash -c, not via a pipe without a TTY." | |
| exit 1 | |
| fi | |
| fi | |
| read -r -s -p "Workspace token: " TOKEN < "$INPUT" | |
| printf "\n" | |
| if [ -z "${TOKEN}" ]; then | |
| echo "Error: token cannot be empty." | |
| exit 1 | |
| fi | |
| PS3="Select your MCP client: " | |
| options=( | |
| "Claude Desktop (macOS)" | |
| "Claude Desktop (Windows)" | |
| "Claude Code (project)" | |
| "Claude Code (global)" | |
| "Continue (VSCode)" | |
| "Other MCP client (Codex, Gemini, Cursor, etc.)" | |
| "Print JSON only (no file changes)" | |
| ) | |
| CONFIG="" | |
| FORMAT="" | |
| select opt in "${options[@]}"; do | |
| case "$REPLY" in | |
| 1) | |
| CONFIG="$HOME/Library/Application Support/Claude/claude_desktop_config.json" | |
| FORMAT="object" | |
| break | |
| ;; | |
| 2) | |
| BASE_DIR="${APPDATA:-$HOME/AppData/Roaming}" | |
| CONFIG="$BASE_DIR/Claude/claude_desktop_config.json" | |
| FORMAT="object" | |
| break | |
| ;; | |
| 3) | |
| CONFIG="$HOME/.claude.json" | |
| FORMAT="claude_code_project" | |
| read -r -p "Project path [${PWD}]: " PROJECT_PATH < "$INPUT" | |
| if [ -z "$PROJECT_PATH" ]; then | |
| PROJECT_PATH="$PWD" | |
| fi | |
| break | |
| ;; | |
| 4) | |
| CONFIG="$HOME/.claude.json" | |
| FORMAT="claude_code_global" | |
| break | |
| ;; | |
| 5) | |
| CONFIG="$HOME/.continue/config.json" | |
| FORMAT="array" | |
| break | |
| ;; | |
| 6) | |
| read -r -p "Config path: " CONFIG < "$INPUT" | |
| if [ -z "$CONFIG" ]; then | |
| echo "Error: config path is required." | |
| exit 1 | |
| fi | |
| read -r -p "Config format (object/array/print) [object]: " FORMAT < "$INPUT" | |
| FORMAT="${FORMAT,,}" | |
| if [ -z "$FORMAT" ]; then | |
| FORMAT="object" | |
| fi | |
| if [ "$FORMAT" != "object" ] && [ "$FORMAT" != "array" ] && [ "$FORMAT" != "print" ]; then | |
| echo "Error: format must be object, array, or print." | |
| exit 1 | |
| fi | |
| break | |
| ;; | |
| 7) | |
| FORMAT="print" | |
| break | |
| ;; | |
| *) | |
| echo "Invalid selection." | |
| ;; | |
| esac | |
| done < "$INPUT" | |
| if [ "$FORMAT" != "print" ]; then | |
| if [ -z "$CONFIG" ]; then | |
| echo "Error: config path is required." | |
| exit 1 | |
| fi | |
| mkdir -p "$(dirname "$CONFIG")" | |
| fi | |
| TOKEN="$TOKEN" CONFIG="$CONFIG" FORMAT="$FORMAT" PROJECT_PATH="${PROJECT_PATH:-}" python3 - <<'PY' | |
| import json | |
| import os | |
| import sys | |
| from pathlib import Path | |
| token = os.environ.get("TOKEN", "").strip() | |
| config_path = os.environ.get("CONFIG", "") | |
| fmt = os.environ.get("FORMAT", "object") | |
| project_path = os.environ.get("PROJECT_PATH", "").strip() | |
| payload = { | |
| "url": "https://mcp.linkbreakers.com", | |
| "headers": {"Authorization": f"Bearer {token}"}, | |
| } | |
| if fmt == "print": | |
| print("\nClaude/obj config:") | |
| print(json.dumps({"mcpServers": {"linkbreakers": payload}}, indent=2)) | |
| print("\nArray config (Continue-style):") | |
| print(json.dumps({"mcpServers": [{"name": "linkbreakers", **payload}]}, indent=2)) | |
| sys.exit(0) | |
| if not config_path: | |
| raise SystemExit("Missing config path.") | |
| path = Path(config_path) | |
| data = {} | |
| if path.exists(): | |
| try: | |
| data = json.loads(path.read_text()) | |
| except json.JSONDecodeError: | |
| data = {} | |
| if fmt == "object": | |
| if not isinstance(data.get("mcpServers"), dict): | |
| data["mcpServers"] = {} | |
| # Always overwrite any existing Linkbreakers entry | |
| if "linkbreakers" in data["mcpServers"]: | |
| del data["mcpServers"]["linkbreakers"] | |
| data["mcpServers"]["linkbreakers"] = payload | |
| elif fmt == "claude_code_project": | |
| if not project_path: | |
| raise SystemExit("Project path is required for Claude Code project config.") | |
| projects = data.get("projects") | |
| if not isinstance(projects, dict): | |
| projects = {} | |
| proj = projects.get(project_path) | |
| if not isinstance(proj, dict): | |
| proj = {} | |
| mcp = proj.get("mcpServers") | |
| if not isinstance(mcp, dict): | |
| mcp = {} | |
| mcp["linkbreakers"] = payload | |
| proj["mcpServers"] = mcp | |
| projects[project_path] = proj | |
| data["projects"] = projects | |
| elif fmt == "claude_code_global": | |
| if not isinstance(data.get("mcpServers"), dict): | |
| data["mcpServers"] = {} | |
| data["mcpServers"]["linkbreakers"] = payload | |
| elif fmt == "array": | |
| servers = data.get("mcpServers") | |
| if not isinstance(servers, list): | |
| servers = [] | |
| servers = [s for s in servers if not (isinstance(s, dict) and s.get("name") == "linkbreakers")] | |
| servers.append({"name": "linkbreakers", **payload}) | |
| data["mcpServers"] = servers | |
| else: | |
| raise SystemExit(f"Unsupported format: {fmt}") | |
| path.write_text(json.dumps(data, indent=2) + "\n") | |
| print(f"\nDone: Linkbreakers MCP configured in {path}") | |
| PY | |
| printf "\n${GREEN}All set.${RESET}\n" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment