Files
dotfiles/mcp-config/install.sh
T
noconnorandClaude Opus 4.8 cb89478016 mcp-config: write the sync hook to ~/.zshrc.local, not ~/.zshrc
~/.zshrc is MANAGED: zsh/install.sh overwrites it wholesale (cp) on every
bootstrap run. install.sh appended the mcp-sync hook to that same file, so
the next bootstrap silently deleted it -- sync.sh then never ran, so
OPENCODE_CONFIG was never exported and opencode came up with no models and
no skills. It looked like a broken gateway or a bad model; it was a wiped
shell hook.

~/.zshrc.local is the unmanaged file the managed zshrc sources last, so the
hook now survives a re-bootstrap. Verified: hook lands in ~/.zshrc.local
(0600), managed ~/.zshrc is left untouched, and OPENCODE_CONFIG still
exports after simulating the bootstrap overwrite.

Also warn instead of failing silently when python3 is missing: sync.sh then
deploys the base config verbatim with an EMPTY models map, which presents as
"the gateway has no models" rather than "a dependency is absent".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:29:07 -04:00

89 lines
3.4 KiB
Bash

#!/usr/bin/env sh
# One-time bootstrap for the covert-gpt MCP gateway on a user's laptop.
#
# curl -fsSL https://git.nic-oconnor.com/public/dotfiles/raw/branch/main/mcp-config/install.sh | sh
#
# It is interactive (prompts for the user's LiteLLM key) UNLESS LITELLM_KEY is
# already set in the environment, e.g.:
# curl -fsSL .../install.sh | LITELLM_KEY=sk-... sh
#
# What it installs (all under the user's home, no root):
# ~/.config/mcp-sync/sync.sh the per-shell refresh hook (from Gitea)
# ~/.config/mcp-sync/key the user's LiteLLM virtual key (chmod 600)
# a line in the user's shell rc that sources sync.sh on each shell start
# After this, every new shell refreshes the gateway config automatically.
set -eu
RAW_BASE="${MCP_SYNC_RAW_BASE:-https://git.nic-oconnor.com/public/dotfiles/raw/branch/main/mcp-config}"
SYNC_HOME="$HOME/.config/mcp-sync"
SYNC_SH="$SYNC_HOME/sync.sh"
KEYFILE="$SYNC_HOME/key"
HOOK_MARKER="# >>> covert-gpt mcp-sync >>>"
say() { printf '%s\n' "$*" >&2; }
command -v curl >/dev/null 2>&1 || { say "error: curl is required"; exit 1; }
mkdir -p "$SYNC_HOME"
# --- 1. fetch the sync hook ------------------------------------------------
say "Fetching mcp-sync hook..."
curl -fsSL -m 15 "$RAW_BASE/sync.sh" -o "$SYNC_SH"
chmod 0644 "$SYNC_SH"
# --- 2. capture the LiteLLM key -------------------------------------------
if [ "${LITELLM_KEY:-}" = "" ]; then
# Read from the controlling TTY since stdin is the piped script.
if [ -r /dev/tty ]; then
printf 'Paste your LiteLLM virtual key (sk-...): ' >&2
IFS= read -r LITELLM_KEY < /dev/tty
else
say "error: no LITELLM_KEY in env and no TTY to prompt."
say "re-run as: curl ... | LITELLM_KEY=sk-... sh"
exit 1
fi
fi
LITELLM_KEY="$(printf '%s' "$LITELLM_KEY" | tr -d ' \t\r\n')"
case "$LITELLM_KEY" in
sk-*) : ;;
*) say "warning: key does not start with 'sk-' — continuing anyway." ;;
esac
printf '%s' "$LITELLM_KEY" > "$KEYFILE"
chmod 0600 "$KEYFILE"
say "Key stored at $KEYFILE (0600)."
# --- 3. wire the shell rc --------------------------------------------------
# For zsh the hook goes in ~/.zshrc.local, NOT ~/.zshrc. The dotfiles repo
# MANAGES ~/.zshrc and overwrites it wholesale on every bootstrap
# (zsh/install.sh), so a hook written there survives only until the next
# bootstrap run — and then models and skills silently vanish, because sync.sh
# never runs and OPENCODE_CONFIG is never exported. ~/.zshrc.local is the
# unmanaged file the managed zshrc sources last, so the hook persists.
case "${SHELL:-}" in
*zsh) RC="$HOME/.zshrc.local" ;;
*bash) RC="$HOME/.bashrc" ;;
*) [ -f "$HOME/.zshrc" ] && RC="$HOME/.zshrc.local" || RC="$HOME/.bashrc" ;;
esac
touch "$RC"
# It sits alongside the user's secrets; keep it non-readable by others.
[ "$RC" = "$HOME/.zshrc.local" ] && chmod 0600 "$RC" 2>/dev/null || true
if grep -qF "$HOOK_MARKER" "$RC" 2>/dev/null; then
say "Shell hook already present in $RC."
else
{
printf '\n%s\n' "$HOOK_MARKER"
printf '%s\n' '[ -f "$HOME/.config/mcp-sync/sync.sh" ] && . "$HOME/.config/mcp-sync/sync.sh"'
printf '%s\n' "# <<< covert-gpt mcp-sync <<<"
} >> "$RC"
say "Added mcp-sync hook to $RC."
fi
# --- 4. run it once now so the config exists immediately -------------------
# shellcheck disable=SC1090
. "$SYNC_SH" || true
say ""
say "Done. Open a new terminal (or 'source $RC') and run opencode."
say "The gateway config refreshes automatically on each new shell."