mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-02 00:04:45 -08:00
Remove unused MCP resources and update documentation
- Remove array_status, system_info, notifications_overview, and parity_status resources - Keep only logs_stream resource (unraid://logs/stream) which is working properly - Update README.md with current resource documentation and modern docker compose syntax - Fix import path issues that were causing subscription errors - Update environment configuration examples - Clean up subscription manager to only include working log streaming 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
400
dev.sh
Executable file
400
dev.sh
Executable file
@@ -0,0 +1,400 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Unraid MCP Server Development Script
|
||||
# Safely manages server processes during development with accurate process detection
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
DEFAULT_PORT=6970
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOG_FILE="$PROJECT_DIR/dev.log"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Helper function for colored output
|
||||
log() {
|
||||
echo -e "${2:-$NC}[$(date +'%H:%M:%S')] $1${NC}"
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Get port from environment or use default
|
||||
get_port() {
|
||||
local port="${UNRAID_MCP_PORT:-$DEFAULT_PORT}"
|
||||
echo "$port"
|
||||
}
|
||||
|
||||
# Find processes using multiple detection methods
|
||||
find_server_processes() {
|
||||
local port=$(get_port)
|
||||
local pids=()
|
||||
|
||||
# Method 1: Command line pattern matching
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" ]]; then
|
||||
local pid=$(echo "$line" | awk '{print $2}')
|
||||
local cmd=$(echo "$line" | awk '{for(i=11;i<=NF;i++) printf "%s ", $i; print ""}')
|
||||
pids+=("$pid")
|
||||
fi
|
||||
done < <(ps aux | grep -E 'python.*unraid.*mcp|python.*main\.py|uv run.*main\.py|uv run -m unraid_mcp' | grep -v grep | grep -v "$0")
|
||||
|
||||
# Method 2: Port binding verification
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" ]]; then
|
||||
local pid=$(echo "$line" | awk '{print $2}')
|
||||
# Add to pids if not already present
|
||||
if [[ ! " ${pids[@]} " =~ " $pid " ]]; then
|
||||
pids+=("$pid")
|
||||
fi
|
||||
fi
|
||||
done < <(lsof -i ":$port" 2>/dev/null | grep LISTEN || true)
|
||||
fi
|
||||
|
||||
# Method 3: Working directory verification
|
||||
local verified_pids=()
|
||||
for pid in "${pids[@]}"; do
|
||||
# Skip if not a valid PID
|
||||
if ! [[ "$pid" =~ ^[0-9]+$ ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -d "/proc/$pid" ]]; then
|
||||
local pwd_info=""
|
||||
if command -v pwdx >/dev/null 2>&1; then
|
||||
pwd_info=$(pwdx "$pid" 2>/dev/null | cut -d' ' -f2- || echo "unknown")
|
||||
else
|
||||
pwd_info=$(readlink -f "/proc/$pid/cwd" 2>/dev/null || echo "unknown")
|
||||
fi
|
||||
|
||||
# Verify it's running from our project directory or a parent directory
|
||||
if [[ "$pwd_info" == "$PROJECT_DIR"* ]] || [[ "$pwd_info" == *"unraid-mcp"* ]]; then
|
||||
verified_pids+=("$pid")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Output final list
|
||||
printf '%s\n' "${verified_pids[@]}" | grep -E '^[0-9]+$' || true
|
||||
}
|
||||
|
||||
# Terminate a process gracefully, then forcefully if needed
|
||||
terminate_process() {
|
||||
local pid=$1
|
||||
local name=${2:-"process"}
|
||||
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
log "Process $pid ($name) already terminated" "$YELLOW"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Terminating $name (PID: $pid)..." "$YELLOW"
|
||||
|
||||
# Step 1: Graceful shutdown (SIGTERM)
|
||||
log " → Sending SIGTERM to PID $pid" "$BLUE"
|
||||
kill -TERM "$pid" 2>/dev/null || {
|
||||
log " Failed to send SIGTERM (process may have died)" "$YELLOW"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Step 2: Wait for graceful shutdown (5 seconds)
|
||||
local count=0
|
||||
while [[ $count -lt 5 ]]; do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
log " ✓ Process $pid terminated gracefully" "$GREEN"
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
((count++))
|
||||
log " Waiting for graceful shutdown... (${count}/5)" "$BLUE"
|
||||
done
|
||||
|
||||
# Step 3: Force kill (SIGKILL)
|
||||
log " → Graceful shutdown timeout, sending SIGKILL to PID $pid" "$RED"
|
||||
kill -KILL "$pid" 2>/dev/null || {
|
||||
log " Failed to send SIGKILL (process may have died)" "$YELLOW"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Step 4: Final verification
|
||||
sleep 1
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
log " ✗ Failed to terminate process $pid" "$RED"
|
||||
return 1
|
||||
else
|
||||
log " ✓ Process $pid terminated forcefully" "$GREEN"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop all server processes
|
||||
stop_servers() {
|
||||
log "🛑 Stopping existing server processes..." "$RED"
|
||||
|
||||
local pids=($(find_server_processes))
|
||||
|
||||
if [[ ${#pids[@]} -eq 0 ]]; then
|
||||
log "No processes to stop" "$GREEN"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local failed=0
|
||||
for pid in "${pids[@]}"; do
|
||||
if ! terminate_process "$pid" "Unraid MCP Server"; then
|
||||
((failed++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Wait for ports to be released
|
||||
local port=$(get_port)
|
||||
log "Waiting for port $port to be released..." "$BLUE"
|
||||
local port_wait=0
|
||||
while [[ $port_wait -lt 3 ]]; do
|
||||
if ! lsof -i ":$port" >/dev/null 2>&1; then
|
||||
log "✓ Port $port released" "$GREEN"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
((port_wait++))
|
||||
done
|
||||
|
||||
if [[ $failed -gt 0 ]]; then
|
||||
log "⚠️ Failed to stop $failed process(es)" "$RED"
|
||||
return 1
|
||||
else
|
||||
log "✅ All processes stopped successfully" "$GREEN"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Start the new modular server
|
||||
start_modular_server() {
|
||||
log "🚀 Starting modular server..." "$GREEN"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Check if main.py exists in unraid_mcp/
|
||||
if [[ ! -f "unraid_mcp/main.py" ]]; then
|
||||
log "❌ unraid_mcp/main.py not found. Make sure modular server is implemented." "$RED"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Start server in background using module syntax
|
||||
log " → Executing: uv run -m unraid_mcp.main" "$BLUE"
|
||||
nohup uv run -m unraid_mcp.main >> "$LOG_FILE" 2>&1 &
|
||||
local pid=$!
|
||||
|
||||
# Give it a moment to start
|
||||
sleep 2
|
||||
|
||||
# Check if it's still running
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
local port=$(get_port)
|
||||
log "✅ Modular server started successfully (PID: $pid, Port: $port)" "$GREEN"
|
||||
log "📋 Process info: $(ps -p "$pid" -o pid,ppid,cmd --no-headers 2>/dev/null || echo 'Process info unavailable')" "$BLUE"
|
||||
|
||||
# Auto-tail logs after successful start
|
||||
echo ""
|
||||
log "📄 Following server logs in real-time..." "$GREEN"
|
||||
log "Press Ctrl+C to stop following logs (server will continue running)" "$YELLOW"
|
||||
echo ""
|
||||
echo -e "${GREEN}=== Following Server Logs (Press Ctrl+C to exit) ===${NC}"
|
||||
tail -f "$LOG_FILE"
|
||||
|
||||
return 0
|
||||
else
|
||||
log "❌ Modular server failed to start" "$RED"
|
||||
log "📄 Check $LOG_FILE for error details" "$YELLOW"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Start the original server
|
||||
start_original_server() {
|
||||
log "🚀 Starting original server..." "$GREEN"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Check if original server exists
|
||||
if [[ ! -f "unraid_mcp_server.py" ]]; then
|
||||
log "❌ unraid_mcp_server.py not found" "$RED"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Start server in background
|
||||
log " → Executing: uv run unraid_mcp_server.py" "$BLUE"
|
||||
nohup uv run unraid_mcp_server.py >> "$LOG_FILE" 2>&1 &
|
||||
local pid=$!
|
||||
|
||||
# Give it a moment to start
|
||||
sleep 2
|
||||
|
||||
# Check if it's still running
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
local port=$(get_port)
|
||||
log "✅ Original server started successfully (PID: $pid, Port: $port)" "$GREEN"
|
||||
log "📋 Process info: $(ps -p "$pid" -o pid,ppid,cmd --no-headers 2>/dev/null || echo 'Process info unavailable')" "$BLUE"
|
||||
|
||||
# Auto-tail logs after successful start
|
||||
echo ""
|
||||
log "📄 Following server logs in real-time..." "$GREEN"
|
||||
log "Press Ctrl+C to stop following logs (server will continue running)" "$YELLOW"
|
||||
echo ""
|
||||
echo -e "${GREEN}=== Following Server Logs (Press Ctrl+C to exit) ===${NC}"
|
||||
tail -f "$LOG_FILE"
|
||||
|
||||
return 0
|
||||
else
|
||||
log "❌ Original server failed to start" "$RED"
|
||||
log "📄 Check $LOG_FILE for error details" "$YELLOW"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Show usage information
|
||||
show_usage() {
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Development script for Unraid MCP Server"
|
||||
echo ""
|
||||
echo "OPTIONS:"
|
||||
echo " (no args) Stop existing servers, start modular server, and tail logs"
|
||||
echo " --old Stop existing servers, start original server, and tail logs"
|
||||
echo " --kill Stop existing servers only (don't start new one)"
|
||||
echo " --status Show status of running servers"
|
||||
echo " --logs [N] Show last N lines of server logs (default: 50)"
|
||||
echo " --tail Follow server logs in real-time (without restarting server)"
|
||||
echo " --help, -h Show this help message"
|
||||
echo ""
|
||||
echo "ENVIRONMENT VARIABLES:"
|
||||
echo " UNRAID_MCP_PORT Port for server (default: $DEFAULT_PORT)"
|
||||
echo ""
|
||||
echo "EXAMPLES:"
|
||||
echo " ./dev.sh # Restart with modular server"
|
||||
echo " ./dev.sh --old # Restart with original server"
|
||||
echo " ./dev.sh --kill # Stop all servers"
|
||||
echo " ./dev.sh --status # Check server status"
|
||||
echo " ./dev.sh --logs # Show last 50 lines of logs"
|
||||
echo " ./dev.sh --logs 100 # Show last 100 lines of logs"
|
||||
echo " ./dev.sh --tail # Follow logs in real-time"
|
||||
}
|
||||
|
||||
# Show server status
|
||||
show_status() {
|
||||
local port=$(get_port)
|
||||
log "🔍 Server Status Check" "$BLUE"
|
||||
log "Project Directory: $PROJECT_DIR" "$BLUE"
|
||||
log "Expected Port: $port" "$BLUE"
|
||||
echo ""
|
||||
|
||||
local pids=($(find_server_processes))
|
||||
|
||||
if [[ ${#pids[@]} -eq 0 ]]; then
|
||||
log "Status: No servers running" "$YELLOW"
|
||||
else
|
||||
log "Status: ${#pids[@]} server(s) running" "$GREEN"
|
||||
for pid in "${pids[@]}"; do
|
||||
local cmd=$(ps -p "$pid" -o cmd --no-headers 2>/dev/null || echo "Command unavailable")
|
||||
log " PID $pid: $cmd" "$GREEN"
|
||||
done
|
||||
fi
|
||||
|
||||
# Check port binding
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
local port_info=$(lsof -i ":$port" 2>/dev/null | grep LISTEN || echo "")
|
||||
if [[ -n "$port_info" ]]; then
|
||||
log "Port $port: BOUND" "$GREEN"
|
||||
echo "$port_info" | while IFS= read -r line; do
|
||||
log " $line" "$BLUE"
|
||||
done
|
||||
else
|
||||
log "Port $port: FREE" "$YELLOW"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Tail the server logs
|
||||
tail_logs() {
|
||||
local lines="${1:-50}"
|
||||
|
||||
log "📄 Tailing last $lines lines from server logs..." "$BLUE"
|
||||
|
||||
if [[ ! -f "$LOG_FILE" ]]; then
|
||||
log "❌ Log file not found: $LOG_FILE" "$RED"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}=== Server Logs (last $lines lines) ===${NC}"
|
||||
tail -n "$lines" "$LOG_FILE"
|
||||
echo -e "${YELLOW}=== End of Logs ===${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Follow server logs in real-time
|
||||
follow_logs() {
|
||||
log "📄 Following server logs in real-time..." "$GREEN"
|
||||
log "Press Ctrl+C to stop following" "$YELLOW"
|
||||
|
||||
if [[ ! -f "$LOG_FILE" ]]; then
|
||||
log "❌ Log file not found: $LOG_FILE" "$RED"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}=== Following Server Logs (Press Ctrl+C to exit) ===${NC}"
|
||||
tail -f "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Main script logic
|
||||
main() {
|
||||
# Initialize log file
|
||||
echo "=== Dev Script Started at $(date) ===" >> "$LOG_FILE"
|
||||
|
||||
case "${1:-}" in
|
||||
--help|-h)
|
||||
show_usage
|
||||
;;
|
||||
--status)
|
||||
show_status
|
||||
;;
|
||||
--kill)
|
||||
stop_servers
|
||||
;;
|
||||
--logs)
|
||||
tail_logs "${2:-50}"
|
||||
;;
|
||||
--tail)
|
||||
follow_logs
|
||||
;;
|
||||
--old)
|
||||
if stop_servers; then
|
||||
start_original_server
|
||||
else
|
||||
log "❌ Failed to stop existing servers" "$RED"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"")
|
||||
if stop_servers; then
|
||||
start_modular_server
|
||||
else
|
||||
log "❌ Failed to stop existing servers" "$RED"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
log "❌ Unknown option: $1" "$RED"
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Run main function with all arguments
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user