feat(toggle-external): manage Magic MCP (21st-dev) — installed disabled by default

Add `magic` to the unified toggle-external.sh helper alongside gstack,
emil-design-eng, darwin-skill, find-skills. MCPs are toggled via
`claude mcp add|remove` instead of symlink moves.

API key loaded from $REPO/.env (gitignored) via .env.example template.
install-plugins.sh step 8.7 forces magic MCP off after each install run
so the MCP doesn't load into every session unless explicitly enabled.

Toggle: bash lib/toggle-external.sh enable|disable|status magic

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
bastien 2026-04-21 20:28:03 +02:00
parent fe7c34ac17
commit ec41d78209
4 changed files with 89 additions and 1 deletions

6
.env.example Normal file
View File

@ -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

4
.gitignore vendored
View File

@ -66,6 +66,10 @@ graphify-out/
# Install logs # Install logs
install-*.log install-*.log
# Local secrets (MCP API keys etc.) — use .env.example as template
.env
.env.local
# OS # OS
.DS_Store .DS_Store
Thumbs.db Thumbs.db

View File

@ -500,6 +500,38 @@ else
fi fi
echo "" 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) # 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 " 🔄 emil-design-eng — UI polish, animations, component craft (curl → symlink)"
echo " 🔄 darwin-skill — autonomous skill optimizer (npx skills, ~/.agents/skills/)" echo " 🔄 darwin-skill — autonomous skill optimizer (npx skills, ~/.agents/skills/)"
echo " 🔄 find-skills — skill discovery helper (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 ""
echo " All plugins installed at: user scope (~/.claude/plugins/)" echo " All plugins installed at: user scope (~/.claude/plugins/)"
echo " GStack skills symlinked individually into ~/.claude/skills/ (→ submodule)" echo " GStack skills symlinked individually into ~/.claude/skills/ (→ submodule)"

View File

@ -8,6 +8,8 @@
# as symlinks inside skills/. This script moves those symlinks # as symlinks inside skills/. This script moves those symlinks
# to/from skills-disabled/ so Claude Code stops/starts scanning them. # to/from skills-disabled/ so Claude Code stops/starts scanning them.
# #
# MCP servers are toggled via `claude mcp add|remove` (not symlinks).
#
# Usage: # Usage:
# toggle-external.sh list # toggle-external.sh list
# toggle-external.sh status <tool> # toggle-external.sh status <tool>
@ -19,6 +21,7 @@
# emil-design-eng — single symlink → skills-external/emil-design-eng # emil-design-eng — single symlink → skills-external/emil-design-eng
# darwin-skill — single symlink → ~/.agents/skills/darwin-skill # darwin-skill — single symlink → ~/.agents/skills/darwin-skill
# find-skills — single symlink → ~/.agents/skills/find-skills # find-skills — single symlink → ~/.agents/skills/find-skills
# magic — 21st-dev Magic MCP server (API key in .env)
# ============================================================ # ============================================================
set -euo pipefail set -euo pipefail
@ -32,7 +35,18 @@ warn() { echo -e "${YELLOW}⚠${NC} $1"; }
err() { echo -e "${RED}${NC} $1"; } err() { echo -e "${RED}${NC} $1"; }
# All non-plugin tools this script can toggle. # 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". # Prints the names (directory basenames) that belong to "gstack".
# Source of truth: skills-external/gstack/*/SKILL.md. The repo's # 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; } [ -d "$HOME/.agents/skills/$tool" ] || { echo "missing"; return; }
[ -e "$SKILLS_DIR/$tool" ] && echo "enabled" || echo "disabled" [ -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 ;; echo "unknown"; return 1 ;;
esac esac
@ -97,6 +119,14 @@ disable_tool() {
warn "$tool already disabled" warn "$tool already disabled"
fi 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 ;; *) err "Unknown tool: $tool"; return 1 ;;
esac esac
} }
@ -134,6 +164,21 @@ enable_tool() {
return 1 return 1
fi 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 ;; *) err "Unknown tool: $tool"; return 1 ;;
esac esac
} }