#!/bin/bash # MCP Server Manager - Start, stop, and manage MCP servers set -euo pipefail MCP_DIR="${HOME}/.claude/mcp-servers" REGISTRY="${MCP_DIR}/registry.json" PID_DIR="${MCP_DIR}/pids" LOG_DIR="${MCP_DIR}/logs" mkdir -p "$PID_DIR" "$LOG_DIR" log() { echo "[$(date -u +"%Y-%m-%d %H:%M:%S UTC")] [mcp-manager] $*" | tee -a "${LOG_DIR}/manager.log" } start_server() { local server_name="$1" local server_config # Get server config from registry server_config=$(jq -r ".servers.${server_name}" "$REGISTRY" 2>/dev/null) if [[ "$server_config" == "null" ]]; then log "ERROR: Server '${server_name}' not found in registry" return 1 fi local enabled=$(echo "$server_config" | jq -r '.enabled // false') if [[ "$enabled" != "true" ]]; then log "Server '${server_name}' is disabled" return 0 fi local pid_file="${PID_DIR}/${server_name}.pid" if [[ -f "$pid_file" ]]; then local pid=$(cat "$pid_file") if kill -0 "$pid" 2>/dev/null; then log "Server '${server_name}' already running (PID: ${pid})" return 0 fi fi local command=$(echo "$server_config" | jq -r '.command') local args=$(echo "$server_config" | jq -r '.args[]' | sed 's/^/"/;s/$/" ' | tr '\n' ' ') log "Starting server '${server_name}': ${command} ${args}" eval "nohup ${command} ${args} > ${LOG_DIR}/${server_name}.log 2>&1 &" local pid=$! echo "$pid" > "$pid_file" sleep 1 if kill -0 "$pid" 2>/dev/null; then log "Server '${server_name}' started (PID: ${pid})" return 0 else log "ERROR: Failed to start server '${server_name}'" return 1 fi } stop_server() { local server_name="$1" local pid_file="${PID_DIR}/${server_name}.pid" if [[ ! -f "$pid_file" ]]; then log "Server '${server_name}' not running" return 0 fi local pid=$(cat "$pid_file") log "Stopping server '${server_name}' (PID: ${pid})..." kill "$pid" 2>/dev/null || true rm -f "$pid_file" log "Server '${server_name}' stopped" } start_all() { local servers=$(jq -r '.servers | keys[]' "$REGISTRY") for server in $servers; do start_server "$server" || true done } stop_all() { local pid_files pid_files=$(ls "$PID_DIR"/*.pid 2>/dev/null || true) for pid_file in $pid_files; do local server_name=$(basename "$pid_file" .pid) stop_server "$server_name" done } status() { echo "=== MCP Server Status ===" echo "" local servers=$(jq -r '.servers | keys[]' "$REGISTRY") for server in $servers; do local enabled=$(jq -r ".servers.${server}.enabled // false" "$REGISTRY") local pid_file="${PID_DIR}/${server}.pid" local status="stopped" if [[ -f "$pid_file" ]]; then local pid=$(cat "$pid_file") if kill -0 "$pid" 2>/dev/null; then status="running (PID: ${pid})" fi fi local icon="🔴" if [[ "$status" == "stopped" ]]; then [[ "$enabled" == "true" ]] && icon="⚪" || icon="⏸️" else icon="🟢" fi local name=$(jq -r ".servers.${server}.name" "$REGISTRY") local category=$(jq -r ".servers.${server}.category // \"other\"" "$REGISTRY") printf "%s %-20s [%-10s] %s\n" "$icon" "$server" "$category" "$status" done } main() { local command="${1:-status}" case "$command" in start) if [[ -n "${2:-}" ]]; then start_server "$2" else start_all fi ;; stop) if [[ -n "${2:-}" ]]; then stop_server "$2" else stop_all fi ;; restart) stop_all sleep 2 start_all ;; status) status ;; list) jq -r '.servers | keys[]' "$REGISTRY" ;; *) echo "Usage: $0 {start|stop|restart|status|list} [server_name]" exit 1 ;; esac } main "$@"