=== run-advancedmd-mcp.sh wrapper === #!/usr/bin/env bash # advancedmd-mcp supervisor. # # Streamable HTTP MCP server on port 18812. Bun + restart-on-crash. # Locked with flock so multiple invocations are safe. set -euo pipefail LOCK_FILE="/tmp/advancedmd-mcp.lock" LOG_FILE="/tmp/advancedmd-mcp.log" HEALTH_FILE="/tmp/advancedmd-mcp-health.json" ENV_FILE="$HOME/.config/advancedmd-mcp.env" RESTART_DELAY=3 STABILITY_THRESHOLD=60 SERVER_DIR="$HOME/repos/exult-agent/tools/advancedmd-mcp" cleanup() { rm -f "$LOCK_FILE" 2>/dev/null || true } trap cleanup EXIT # Single-instance guard if [ -f "$LOCK_FILE" ]; then other=$(cat "$LOCK_FILE" 2>/dev/null || true) if [ -n "$other" ] && kill -0 "$other" 2>/dev/null; then echo "[$(date)] another instance running (pid $other). Exiting." >&2 exit 0 fi rm -f "$LOCK_FILE" fi echo $$ > "$LOCK_FILE" log_msg() { echo "[$(date '+%Y-%m-%dT%H:%M:%S%z')] $1" | tee -a "$LOG_FILE"; } BUN_BIN="$(command -v bun || echo "$HOME/.bun/bin/bun")" [ -x "$BUN_BIN" ] || { log_msg "ERROR: bun binary not found"; exit 1; } [ -d "$SERVER_DIR" ] || { log_msg "ERROR: server dir missing: $SERVER_DIR"; exit 1; } # Load env (AMD creds + MCP_BEARER_TOKEN) if [ -f "$ENV_FILE" ]; then set -a # shellcheck disable=SC1090 source "$ENV_FILE" set +a else log_msg "ERROR: env file missing: $ENV_FILE" exit 1 fi # Required env sanity. Accept either AMD_CREDENTIALS (JSON cred chain) or the # legacy AMD_USERNAME/PASSWORD/OFFICE_KEY trio. if [ -z "${MCP_BEARER_TOKEN:-}" ]; then log_msg "ERROR: MCP_BEARER_TOKEN not set in $ENV_FILE" exit 1 fi if [ -z "${AMD_CREDENTIALS:-}" ]; then for k in AMD_OFFICE_KEY AMD_USERNAME AMD_PASSWORD; do if [ -z "${!k:-}" ]; then log_msg "ERROR: $k not set (and AMD_CREDENTIALS not provided) in $ENV_FILE" exit 1 fi done fi : "${AMD_APPNAME:=TEMP}" export AMD_CREDENTIALS AMD_OFFICE_KEY AMD_USERNAME AMD_PASSWORD AMD_APPNAME MCP_BEARER_TOKEN consecutive_failures=0 last_failure_ts=0 restarts_today=0 backoff() { if [ "$consecutive_failures" -ge 5 ]; then echo 60 elif [ "$consecutive_failures" -ge 3 ]; then echo 15 else echo "$RESTART_DELAY"; fi } while true; do start_ts=$(date +%s) log_msg "starting bun server (port=18812 failures=$consecutive_failures)" "$BUN_BIN" "$SERVER_DIR/server.ts" >>"$LOG_FILE" 2>&1 || true end_ts=$(date +%s) dur=$((end_ts - start_ts)) if [ "$dur" -gt "$STABILITY_THRESHOLD" ]; then consecutive_failures=0 log_msg "session ran ${dur}s (stable)" else if [ "$last_failure_ts" -gt 0 ] && [ $((end_ts - last_failure_ts)) -gt 300 ]; then consecutive_failures=1 else consecutive_failures=$((consecutive_failures + 1)) fi last_failure_ts="$end_ts" log_msg "session ran ${dur}s (consecutive failure #$consecutive_failures)" fi restarts_today=$((restarts_today + 1)) cat >"$HEALTH_FILE" < AMD_OFFICE_KEY= AMD_USERNAME= AMD_PASSWORD= AMD_APPNAME= MCP_BEARER_TOKEN= AMD_ALLOW_WRITES= === amd-agent credentials.env KEYS only === AMD_USER= AMD_OFFICE= AMD_PASSWORD= AMD_SECQ1_Q= AMD_SECQ1_A= AMD_SECQ2_Q= AMD_SECQ2_A= AMD_SECQ3_Q= AMD_SECQ3_A= AMD_SECQ4_Q= AMD_SECQ4_A= AGENT_MS_TOTP_SECRET= CUROGRAM_AGENT_PASSWORD= CUROGRAM_AGENT_LOGIN_URL= CUROGRAM_AGENT_USERNAME= === amd-user.env KEYS only === # AMD User Account (human login, not the ARC022825 API service account) # Use for REST API access requiring user-bound auth (vs the service account). # Login mode: Practice Manager (PM) by default. # 2FA: code arrives at Gautam's Outlook email. AMD_USER_USERNAME= AMD_USER_PASSWORD= AMD_USER_OFFICE_KEY= AMD_USER_DEFAULT_MODE=