Pulse/scripts/install-mcp.sh

188 lines
6.3 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# install-mcp.sh - Install the Pulse MCP server adapter
#
# Detects the local platform/architecture, downloads the matching
# pulse-mcp binary from the latest GitHub Release, verifies the
# SHA256 checksum against the published checksums file, and places
# the binary on PATH.
#
# Usage:
# curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install-mcp.sh | bash
#
# Options (env vars):
# PULSE_MCP_VERSION Override the version to install (e.g. "v6.0.0-rc.5").
# Default: latest.
# PULSE_MCP_BIN_DIR Where to install the binary.
# Default: $HOME/.local/bin if writable, else /usr/local/bin.
# PULSE_MCP_REPO GitHub repo to download from. Default: rcourtman/Pulse.
# PULSE_MCP_NO_VERIFY If "1", skip SHA256 verification (not recommended).
#
# After install, configure your MCP client per `cmd/pulse-mcp/README.md` in the
# Pulse repository (or `docs/AGENT_SUBSTRATE.md` in your installed Pulse server).
#
# pulse-mcp is the stdio JSON-RPC adapter that wraps Pulse's agent
# surface for Claude Desktop, Claude Code, and other MCP clients.
set -euo pipefail
REPO="${PULSE_MCP_REPO:-rcourtman/Pulse}"
VERSION="${PULSE_MCP_VERSION:-latest}"
NO_VERIFY="${PULSE_MCP_NO_VERIFY:-}"
log() {
printf '[install-mcp] %s\n' "$*"
}
err() {
printf '[install-mcp] error: %s\n' "$*" >&2
exit 1
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || err "missing required command: $1"
}
detect_platform() {
local os arch
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
arch="$(uname -m)"
case "$os" in
linux) os="linux" ;;
darwin) os="darwin" ;;
freebsd) os="freebsd" ;;
mingw*|msys*|cygwin*)
err "Windows shells must use install-mcp.ps1 instead. Run via PowerShell:
iwr https://github.com/${REPO}/releases/latest/download/install-mcp.ps1 -UseBasicParsing | iex"
;;
*)
err "unsupported OS: $os"
;;
esac
case "$arch" in
x86_64|amd64) arch="amd64" ;;
aarch64|arm64) arch="arm64" ;;
armv7l|armv7) arch="armv7" ;;
armv6l|armv6) arch="armv6" ;;
i386|i686) arch="386" ;;
*)
err "unsupported architecture: $arch"
;;
esac
# Trim impossible combinations so we fail with a clear message
# rather than a confusing 404 from the GitHub asset endpoint.
case "${os}-${arch}" in
darwin-amd64|darwin-arm64) ;;
linux-amd64|linux-arm64|linux-armv7|linux-armv6|linux-386) ;;
freebsd-amd64|freebsd-arm64) ;;
*)
err "no published pulse-mcp binary for ${os}-${arch}; build from source via go install github.com/rcourtman/pulse-go-rewrite/cmd/pulse-mcp@latest"
;;
esac
printf '%s-%s' "$os" "$arch"
}
choose_install_dir() {
if [ -n "${PULSE_MCP_BIN_DIR:-}" ]; then
printf '%s' "${PULSE_MCP_BIN_DIR}"
return
fi
local home_bin="${HOME}/.local/bin"
if [ -d "${home_bin}" ] && [ -w "${home_bin}" ]; then
printf '%s' "${home_bin}"
return
fi
if mkdir -p "${home_bin}" 2>/dev/null && [ -w "${home_bin}" ]; then
printf '%s' "${home_bin}"
return
fi
printf '%s' "/usr/local/bin"
}
resolve_release_base() {
if [ "${VERSION}" = "latest" ]; then
printf 'https://github.com/%s/releases/latest/download' "${REPO}"
else
printf 'https://github.com/%s/releases/download/%s' "${REPO}" "${VERSION}"
fi
}
main() {
require_cmd curl
require_cmd uname
require_cmd install
local platform install_dir base bin_name url tmp checksums_url checksums_tmp
platform="$(detect_platform)"
install_dir="$(choose_install_dir)"
base="$(resolve_release_base)"
bin_name="pulse-mcp-${platform}"
url="${base}/${bin_name}"
log "platform: ${platform}"
log "install dir: ${install_dir}"
log "downloading: ${url}"
tmp="$(mktemp -t pulse-mcp.XXXXXX)"
trap 'rm -f "${tmp}"' EXIT
if ! curl -fsSL --retry 3 "${url}" -o "${tmp}"; then
err "download failed: ${url}
If a release exists for this version, the binary may not yet be published for ${platform}.
Build from source: go install github.com/rcourtman/pulse-go-rewrite/cmd/pulse-mcp@latest"
fi
if [ "${NO_VERIFY}" != "1" ]; then
local sha_cmd
if command -v sha256sum >/dev/null 2>&1; then
sha_cmd="sha256sum"
elif command -v shasum >/dev/null 2>&1; then
sha_cmd="shasum -a 256"
else
err "no sha256 tool found (sha256sum or shasum). Set PULSE_MCP_NO_VERIFY=1 to skip verification."
fi
checksums_url="${base}/checksums.txt"
checksums_tmp="$(mktemp -t pulse-mcp-sums.XXXXXX)"
trap 'rm -f "${tmp}" "${checksums_tmp}"' EXIT
if ! curl -fsSL --retry 3 "${checksums_url}" -o "${checksums_tmp}"; then
log "warning: could not fetch checksums.txt; skipping verification"
else
local expected actual
expected="$(awk -v name="${bin_name}" '$2 == name {print $1; exit}' "${checksums_tmp}" || true)"
if [ -z "${expected}" ]; then
log "warning: ${bin_name} not listed in checksums.txt; skipping verification"
else
actual="$(${sha_cmd} "${tmp}" | awk '{print $1}')"
if [ "${expected}" != "${actual}" ]; then
err "sha256 mismatch for ${bin_name}: expected ${expected}, got ${actual}"
fi
log "sha256 verified"
fi
fi
fi
install -m 0755 "${tmp}" "${install_dir}/pulse-mcp"
log "installed: ${install_dir}/pulse-mcp"
case ":${PATH}:" in
*":${install_dir}:"*) ;;
*)
log "note: ${install_dir} is not on PATH. Add this line to your shell profile:
export PATH=\"${install_dir}:\$PATH\""
;;
esac
log ""
log "next steps:"
log " 1. Mint a Pulse API token in Settings -> API Access (with monitoring:read,"
log " and monitoring:write if you want the operator-state write tools)."
log " 2. Wire pulse-mcp into your MCP client per the cmd/pulse-mcp/README.md"
log " in the Pulse repository (or docs/AGENT_SUBSTRATE.md in your Pulse install)."
}
main "$@"