diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..55577e3 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +# Local secrets for Claude Code plugin install scripts. +# Copy to .env and fill in real values. .env is gitignored. +# +# Used by: lib/toggle-external.sh enable|disable magic +# Get a key at: https://21st.dev/magic (dashboard → API keys) +MAGIC_API_KEY=your_21st_dev_magic_api_key_here diff --git a/.gitignore b/.gitignore index a18aebc..2c9d901 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,10 @@ graphify-out/ # Install logs install-*.log +# Local secrets (MCP API keys etc.) — use .env.example as template +.env +.env.local + # OS .DS_Store Thumbs.db diff --git a/install-plugins.sh b/install-plugins.sh index 0f8636f..8a65c37 100644 --- a/install-plugins.sh +++ b/install-plugins.sh @@ -500,6 +500,38 @@ else fi echo "" +# ============================================================ +# STEP 8.7 — MAGIC MCP (21st-dev) — installed but DISABLED by default +# ============================================================ +# Magic MCP is a stdio MCP server providing UI component generation +# from 21st.dev. Toggled via lib/toggle-external.sh (same interface as +# gstack, emil-design-eng, etc.). Registered in Claude Code user scope. +# +# Default policy: DISABLED at install time. Rationale: MCP tools load +# into every Claude Code session and consume context tokens. Enable +# only when you're actively using Magic. +# +# API key: read from $REPO/.env (MAGIC_API_KEY=...) — NEVER committed. +# Template: $REPO/.env.example. Get a key at https://21st.dev/magic +echo "── Step 8.7: Magic MCP (21st-dev) ──────────────────────────" +echo "" +if [ -x "$REPO/lib/toggle-external.sh" ]; then + MAGIC_STATUS="$(bash "$REPO/lib/toggle-external.sh" status magic 2>/dev/null || echo missing)" + if [ "$MAGIC_STATUS" = "enabled" ]; then + info "Disabling magic MCP by default (enable on demand)..." + bash "$REPO/lib/toggle-external.sh" disable magic >/dev/null + ok "magic MCP disabled — enable with: bash lib/toggle-external.sh enable magic" + else + ok "magic MCP disabled (default)" + fi + if [ ! -f "$REPO/.env" ] || ! grep -q '^MAGIC_API_KEY=' "$REPO/.env" 2>/dev/null; then + warn "MAGIC_API_KEY not found in $REPO/.env — copy .env.example and set your key before enabling" + fi +else + warn "lib/toggle-external.sh not found or not executable — skipping" +fi +echo "" + # ============================================================ # STEP 9 — SHELL CONFIG (alias + env vars) # ============================================================ @@ -573,6 +605,7 @@ echo " 🔄 graphifyy — codebase knowledge graph (pipx, PreToolUs echo " 🔄 emil-design-eng — UI polish, animations, component craft (curl → symlink)" echo " 🔄 darwin-skill — autonomous skill optimizer (npx skills, ~/.agents/skills/)" echo " 🔄 find-skills — skill discovery helper (npx skills, ~/.agents/skills/)" +echo " 🔄 magic MCP — 21st-dev UI generation MCP (toggle: lib/toggle-external.sh enable magic)" echo "" echo " All plugins installed at: user scope (~/.claude/plugins/)" echo " GStack skills symlinked individually into ~/.claude/skills/ (→ submodule)" diff --git a/lib/toggle-external.sh b/lib/toggle-external.sh index fb94634..7c49bc0 100755 --- a/lib/toggle-external.sh +++ b/lib/toggle-external.sh @@ -8,6 +8,8 @@ # as symlinks inside skills/. This script moves those symlinks # to/from skills-disabled/ so Claude Code stops/starts scanning them. # +# MCP servers are toggled via `claude mcp add|remove` (not symlinks). +# # Usage: # toggle-external.sh list # toggle-external.sh status @@ -19,6 +21,7 @@ # emil-design-eng — single symlink → skills-external/emil-design-eng # darwin-skill — single symlink → ~/.agents/skills/darwin-skill # find-skills — single symlink → ~/.agents/skills/find-skills +# magic — 21st-dev Magic MCP server (API key in .env) # ============================================================ set -euo pipefail @@ -32,7 +35,18 @@ warn() { echo -e "${YELLOW}⚠${NC} $1"; } err() { echo -e "${RED}✗${NC} $1"; } # All non-plugin tools this script can toggle. -MANAGED_TOOLS=(gstack emil-design-eng darwin-skill find-skills) +MANAGED_TOOLS=(gstack emil-design-eng darwin-skill find-skills magic) + +# Load MAGIC_API_KEY (and any other secrets) from $REPO/.env if present. +# Called only by the magic branch — other tools don't need env vars. +load_env() { + if [ -z "${MAGIC_API_KEY:-}" ] && [ -f "$REPO/.env" ]; then + set -a + # shellcheck source=/dev/null + source "$REPO/.env" + set +a + fi +} # Prints the names (directory basenames) that belong to "gstack". # Source of truth: skills-external/gstack/*/SKILL.md. The repo's @@ -65,6 +79,14 @@ status_tool() { [ -d "$HOME/.agents/skills/$tool" ] || { echo "missing"; return; } [ -e "$SKILLS_DIR/$tool" ] && echo "enabled" || echo "disabled" ;; + magic) + command -v claude >/dev/null || { echo "missing"; return; } + if claude mcp list 2>/dev/null | grep -q '^magic:'; then + echo "enabled" + else + echo "disabled" + fi + ;; *) echo "unknown"; return 1 ;; esac @@ -97,6 +119,14 @@ disable_tool() { warn "$tool already disabled" fi ;; + magic) + if [ "$(status_tool magic)" = "enabled" ]; then + claude mcp remove magic -s user >/dev/null + ok "magic disabled" + else + warn "magic already disabled" + fi + ;; *) err "Unknown tool: $tool"; return 1 ;; esac } @@ -134,6 +164,21 @@ enable_tool() { return 1 fi ;; + magic) + load_env + if [ -z "${MAGIC_API_KEY:-}" ]; then + err "MAGIC_API_KEY not set — add it to $REPO/.env (template: .env.example)" + return 1 + fi + if [ "$(status_tool magic)" = "enabled" ]; then + warn "magic already enabled" + return 0 + fi + claude mcp add magic --scope user \ + --env API_KEY="$MAGIC_API_KEY" \ + -- npx -y @21st-dev/magic@latest + ok "magic enabled (user scope)" + ;; *) err "Unknown tool: $tool"; return 1 ;; esac }