#!/bin/bash

# ============================================================================
# Claude Code Statusline - MCP Server Monitoring Module
# ============================================================================
# 
# This module handles all MCP (Model Context Protocol) server monitoring,
# including connection status, server enumeration, and health checking.
#
# Dependencies: core.sh, security.sh
# ============================================================================

# Prevent multiple includes
[[ "${STATUSLINE_MCP_LOADED:-}" == "true" ]] && return 0
export STATUSLINE_MCP_LOADED=true

# Dependencies will be checked during initialization

# ============================================================================
# MCP CONSTANTS
# ============================================================================

# MCP status indicators
export MCP_STATUS_CONNECTED="connected"
export MCP_STATUS_DISCONNECTED="disconnected"
export MCP_STATUS_UNKNOWN="unknown"
export MCP_STATUS_ERROR="error"

# Connection patterns for parsing MCP output
export MCP_CONNECTED_PATTERN="✓ Connected"
export MCP_DISCONNECTED_PATTERN="✗ Disconnected"
export MCP_ERROR_PATTERN="❌ Error"

# ============================================================================
# NATIVE MCP JSON EXTRACTION (Issue #228)
# ============================================================================
# Claude Code sends fresh MCP data on every render via stdin JSON:
#   "mcp": { "servers": [{"name": "ctx7", "status": "connected"}, ...] }
# These functions provide zero-latency, always-fresh MCP data without CLI calls.
# Follows the native-first pattern from lib/cost/native.sh

# Check if native MCP JSON data is available and non-empty
has_native_mcp_data() {
    if [[ -z "${STATUSLINE_INPUT_JSON:-}" ]]; then
        debug_log "MCP native: no STATUSLINE_INPUT_JSON" "INFO"
        return 1
    fi

    local server_count mcp_type
    mcp_type=$(echo "$STATUSLINE_INPUT_JSON" | jq -r '.mcp.servers | type' 2>/dev/null)
    server_count=$(echo "$STATUSLINE_INPUT_JSON" | jq -r '.mcp.servers | if type == "array" and length > 0 then length else empty end' 2>/dev/null)

    debug_log "MCP native: servers type=$mcp_type, count=${server_count:-0}" "INFO"

    [[ -n "$server_count" && "$server_count" -gt 0 ]] 2>/dev/null
}

# Check if native JSON has MCP field (even if empty servers array)
# Returns 0 if .mcp.servers exists as array (including empty [])
# Used to avoid CLI fallback when CC provides authoritative empty data
has_native_mcp_field() {
    [[ -n "${STATUSLINE_INPUT_JSON:-}" ]] || return 1
    local mcp_type
    mcp_type=$(echo "$STATUSLINE_INPUT_JSON" | jq -r '.mcp.servers | type' 2>/dev/null)
    [[ "$mcp_type" == "array" ]]
}

# Parse native MCP servers into "name:status" format (matching CLI parse output)
# Returns: "ctx7:connected,fs:connected,gh:disconnected"
get_native_mcp_servers() {
    if [[ -z "${STATUSLINE_INPUT_JSON:-}" ]]; then
        return 1
    fi

    local servers
    servers=$(echo "$STATUSLINE_INPUT_JSON" | jq -r '
        .mcp.servers // [] |
        if type == "array" and length > 0 then
            map((.name // "unknown") + ":" + (.status // "unknown"))
            | join(",")
        else empty end
    ' 2>/dev/null)

    if [[ -n "$servers" ]]; then
        echo "$servers"
        return 0
    fi
    return 1
}

# Get native MCP status as "connected/total" format
# Returns: "3/3" or "2/3"
get_native_mcp_status() {
    if [[ -z "${STATUSLINE_INPUT_JSON:-}" ]]; then
        return 1
    fi

    local status
    status=$(echo "$STATUSLINE_INPUT_JSON" | jq -r '
        .mcp.servers // [] |
        if type == "array" and length > 0 then
            "\(map(select(.status == "connected")) | length)/\(length)"
        else empty end
    ' 2>/dev/null)

    if [[ -n "$status" ]]; then
        echo "$status"
        return 0
    fi
    return 1
}

# ============================================================================
# MCP SERVER DETECTION
# ============================================================================

# Check if Claude CLI is available
is_claude_cli_available() {
    command_exists claude
}

# Execute claude mcp list command with intelligent caching
execute_mcp_list() {
    local timeout_duration="${1:-$CONFIG_MCP_TIMEOUT}"
    local _in_cc_session="false"

    # Detect active Claude Code session.
    # STATUSLINE_INPUT_JSON is only set when CC pipes JSON to us.
    # Inside CC: use short 3s timeout (CLI works in CC v2.1.85+ but may hang
    # in older versions) and prefer cache. Outside CC: normal timeout.
    # Allow mock claude binaries (integration tests with MOCK_BIN_DIR) to proceed.
    if [[ -n "${STATUSLINE_INPUT_JSON:-}" || "${STATUSLINE_TESTING:-}" == "true" ]]; then
        local _claude_path
        _claude_path=$(command -v claude 2>/dev/null) || return 1
        if [[ -z "${MOCK_BIN_DIR:-}" || "$_claude_path" != "${MOCK_BIN_DIR}"/* ]]; then
            _in_cc_session="true"
            timeout_duration="3s"
        fi
    fi

    if ! is_claude_cli_available; then
        debug_log "Claude CLI not available for MCP monitoring" "WARN"
        return 1
    fi

    # Use universal caching system with repository-aware cache keys
    if [[ "${STATUSLINE_CACHE_LOADED:-}" == "true" ]]; then
        local cache_key
        cache_key=$(generate_typed_cache_key "claude_mcp_list" "mcp")

        # Inside active CC session: prefer cache (any age), fall back to short-timeout CLI
        if [[ "$_in_cc_session" == "true" ]]; then
            local cache_file
            cache_file=$(get_cache_file_path "external_${cache_key}" "true")
            if [[ -f "$cache_file" ]] && validate_command_output "$cache_file"; then
                debug_log "MCP: using cached CLI result inside CC session" "INFO"
                cat "$cache_file" 2>/dev/null
                return 0
            fi
            debug_log "MCP: cache cold, trying CLI with ${timeout_duration} timeout" "INFO"
        fi

        # Normal cache + refresh cycle (short timeout inside CC, normal outside)
        if command_exists timeout; then
            cache_external_command "$cache_key" "$CACHE_DURATION_MCP" "validate_command_output" timeout "$timeout_duration" claude mcp list 2>/dev/null
        elif command_exists gtimeout; then
            cache_external_command "$cache_key" "$CACHE_DURATION_MCP" "validate_command_output" gtimeout "$timeout_duration" claude mcp list 2>/dev/null
        else
            cache_external_command "$cache_key" "$CACHE_DURATION_MCP" "validate_command_output" claude mcp list 2>/dev/null
        fi
    else
        _execute_mcp_list_direct "$timeout_duration"
    fi
}

# Internal function for direct MCP list execution (used by caching)
_execute_mcp_list_direct() {
    local timeout_duration="${1:-$CONFIG_MCP_TIMEOUT}"
    
    # Execute with timeout protection
    if command_exists timeout; then
        timeout "$timeout_duration" claude mcp list 2>/dev/null
    elif command_exists gtimeout; then
        gtimeout "$timeout_duration" claude mcp list 2>/dev/null
    else
        # Fallback without timeout (risky)
        claude mcp list 2>/dev/null
    fi
}

# Parse MCP server list output
parse_mcp_server_list() {
    local mcp_output="$1"
    local servers_data=""
    
    if [[ -z "$mcp_output" ]]; then
        return 1
    fi
    
    while IFS= read -r line; do
        # Skip empty lines and header lines
        [[ -z "$line" ]] && continue
        [[ "$line" =~ ^Checking ]] && continue
        
        # Parse server name using secure parsing
        local server_name
        if server_name=$(parse_mcp_server_name_secure "$line" 2>/dev/null); then
            local server_status="$MCP_STATUS_DISCONNECTED"
            
            # Determine connection status using bash pattern matching (Issue #136)
            # Avoids spawning subshell+grep for each pattern check
            if [[ "$line" == *"$MCP_CONNECTED_PATTERN"* ]]; then
                server_status="$MCP_STATUS_CONNECTED"
            elif [[ "$line" == *"$MCP_DISCONNECTED_PATTERN"* ]]; then
                server_status="$MCP_STATUS_DISCONNECTED"
            elif [[ "$line" == *"$MCP_ERROR_PATTERN"* ]]; then
                server_status="$MCP_STATUS_ERROR"
            else
                server_status="$MCP_STATUS_UNKNOWN"
            fi
            
            # Add to servers data
            if [[ -z "$servers_data" ]]; then
                servers_data="${server_name}:${server_status}"
            else
                servers_data="${servers_data},${server_name}:${server_status}"
            fi
        fi
    done <<<"$mcp_output"
    
    echo "$servers_data"
}

# ============================================================================
# MCP STATUS FUNCTIONS
# ============================================================================

# Get basic MCP server count status (connected/total)
get_mcp_status() {
    start_timer "mcp_status"

    # Native-first: use fresh JSON from Claude Code stdin (Issue #228)
    if has_native_mcp_data; then
        local native_status
        native_status=$(get_native_mcp_status)
        if [[ -n "$native_status" ]]; then
            local status_time
            status_time=$(end_timer "mcp_status")
            debug_log "MCP status from native JSON in ${status_time}s: ${native_status}" "INFO"
            echo "$native_status"
            return 0
        fi
    elif has_native_mcp_field; then
        # Native JSON has .mcp.servers but it's empty — authoritative "0 servers"
        local status_time
        status_time=$(end_timer "mcp_status")
        debug_log "MCP status from native JSON (empty servers): 0/0 in ${status_time}s" "INFO"
        echo "0/0"
        return 0
    elif [[ -n "${STATUSLINE_INPUT_JSON:-}" ]]; then
        # Inside CC session but no mcp field at all — CC doesn't send MCP data
        # Don't fall back to CLI (hangs inside active CC sessions)
        local status_time
        status_time=$(end_timer "mcp_status")
        debug_log "MCP status: inside CC but no mcp field in JSON, returning 0/0" "INFO"
        echo "0/0"
        return 0
    fi

    # Fallback: CLI path (only when running outside CC — no STATUSLINE_INPUT_JSON)
    local mcp_list_output
    if ! mcp_list_output=$(execute_mcp_list); then
        debug_log "Failed to get MCP server list" "WARN"
        local _discard; _discard=$(end_timer "mcp_status")
        echo "?/?"
        return 1
    fi

    # Parse server information
    local servers_data
    servers_data=$(parse_mcp_server_list "$mcp_list_output")

    if [[ -z "$servers_data" ]]; then
        debug_log "No MCP servers found in output" "INFO"
        local _discard; _discard=$(end_timer "mcp_status")
        echo "0/0"
        return 0
    fi

    # Count connected and total servers
    local connected_count=0
    local total_count=0

    # Split servers by comma and count
    local temp_servers="${servers_data}," # Add trailing comma for easier parsing
    local parse_count=0
    local max_servers=50  # Prevent infinite parsing loops

    while [[ "$temp_servers" == *","* ]] && [[ $parse_count -lt $max_servers ]]; do
        local server_entry="${temp_servers%%,*}"
        temp_servers="${temp_servers#*,}"
        parse_count=$((parse_count + 1))

        # Extract server status
        local server_status="${server_entry#*:}"

        total_count=$((total_count + 1))

        if [[ "$server_status" == "$MCP_STATUS_CONNECTED" ]]; then
            connected_count=$((connected_count + 1))
        fi
    done

    local status_time
    status_time=$(end_timer "mcp_status")
    debug_log "MCP status check completed in ${status_time}s: ${connected_count}/${total_count}" "INFO"

    echo "${connected_count}/${total_count}"
}

# Get all MCP servers with their status
get_all_mcp_servers() {
    start_timer "mcp_all_servers"

    # Native-first: use fresh JSON from Claude Code stdin (Issue #228)
    if has_native_mcp_data; then
        local native_servers
        native_servers=$(get_native_mcp_servers)
        if [[ -n "$native_servers" ]]; then
            local all_servers_time
            all_servers_time=$(end_timer "mcp_all_servers")
            debug_log "MCP all servers from native JSON in ${all_servers_time}s" "INFO"
            echo "$native_servers"
            return 0
        fi
    elif has_native_mcp_field; then
        # Native JSON has .mcp.servers but it's empty — authoritative "no servers"
        local all_servers_time
        all_servers_time=$(end_timer "mcp_all_servers")
        debug_log "MCP all servers from native JSON (empty): none in ${all_servers_time}s" "INFO"
        echo "$CONFIG_MCP_NONE_MESSAGE"
        return 0
    elif [[ -n "${STATUSLINE_INPUT_JSON:-}" ]]; then
        # Inside CC session but no mcp field — CC doesn't send MCP data
        local all_servers_time
        all_servers_time=$(end_timer "mcp_all_servers")
        debug_log "MCP all servers: inside CC but no mcp field, returning none" "INFO"
        echo "$CONFIG_MCP_NONE_MESSAGE"
        return 0
    fi

    # Fallback: CLI path with reduced 30s cache (only when no native JSON available)
    local mcp_list_output
    if ! mcp_list_output=$(execute_mcp_list); then
        debug_log "Failed to get MCP server list for all servers" "WARN"
        local _discard; _discard=$(end_timer "mcp_all_servers")
        echo "$CONFIG_MCP_UNKNOWN_MESSAGE"
        return 1
    fi

    local servers_data
    servers_data=$(parse_mcp_server_list "$mcp_list_output")

    local all_servers_time
    all_servers_time=$(end_timer "mcp_all_servers")
    debug_log "MCP all servers check completed in ${all_servers_time}s" "INFO"

    if [[ -n "$servers_data" ]]; then
        echo "$servers_data"
    else
        echo "$CONFIG_MCP_NONE_MESSAGE"
    fi
}

# ============================================================================
# FILE-BASED MCP SERVER DETECTION
# ============================================================================
# Detects MCP servers from project .mcp.json and global settings.json files.
# Provides a config-file-based fallback when CC doesn't send MCP data via stdin.
# SSH servers are probed for connectivity; command-based servers check PATH.

# Parse configured MCP servers from .mcp.json and global settings.json
# Returns lines of "name:command:ssh_host" (ssh_host empty for non-SSH)
get_configured_mcp_servers() {
    local search_dir="${1:-${STATUSLINE_CURRENT_DIR:-$(pwd)}}"
    local mcp_json_file="$search_dir/.mcp.json"
    local servers=""

    # Source 1: Project .mcp.json
    if [[ -f "$mcp_json_file" ]]; then
        local file_servers
        file_servers=$(jq -r '
            .mcpServers // {} | to_entries[] |
            .key as $name |
            .value |
            ($name + ":" + (.command // "unknown") + ":" +
                (if .command == "ssh" then (.args[0] // "" | split("@") | if length > 1 then .[1] else .[0] end) else "" end))
        ' "$mcp_json_file" 2>/dev/null)
        if [[ -n "$file_servers" ]]; then
            servers="$file_servers"
        fi
    fi

    # Source 2: Global settings.json mcpServers
    local global_settings="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json"
    if [[ -f "$global_settings" ]]; then
        local settings_servers
        settings_servers=$(jq -r '
            .mcpServers // {} | to_entries[] |
            .key as $name |
            .value |
            ($name + ":" + (.command // "unknown") + ":" +
                (if .command == "ssh" then (.args[0] // "" | split("@") | if length > 1 then .[1] else .[0] end) else "" end))
        ' "$global_settings" 2>/dev/null)
        if [[ -n "$settings_servers" ]]; then
            if [[ -n "$servers" ]]; then
                servers="$servers"$'\n'"$settings_servers"
            else
                servers="$settings_servers"
            fi
        fi
    fi

    echo "$servers"
}

# Probe SSH server connectivity on port 22
# Returns 0 (success) if reachable, 1 (failure) if not
probe_ssh_server() {
    local host="$1"
    local timeout_sec="${2:-1}"

    if [[ -z "$host" ]]; then
        return 1
    fi

    # Use timeout/gtimeout to hard-kill nc — nc's -w flag is unreliable
    # when ISP silently drops packets (no ICMP unreachable)
    if command_exists nc; then
        if command_exists timeout; then
            timeout "$timeout_sec" nc -z "$host" 22 &>/dev/null
            return $?
        elif command_exists gtimeout; then
            gtimeout "$timeout_sec" nc -z "$host" 22 &>/dev/null
            return $?
        else
            nc -z -w "$timeout_sec" "$host" 22 &>/dev/null
            return $?
        fi
    fi

    # Fallback: bash /dev/tcp with background + kill
    (echo >/dev/tcp/"$host"/22) &>/dev/null &
    local pid=$!
    local i=0
    local max_iter=$(( timeout_sec * 5 ))
    while kill -0 "$pid" 2>/dev/null && [[ $i -lt $max_iter ]]; do
        sleep 0.2
        i=$(( i + 1 ))
    done
    if kill -0 "$pid" 2>/dev/null; then
        kill "$pid" 2>/dev/null
        return 1
    fi
    wait "$pid" 2>/dev/null
    return $?
}

# Get configured MCP servers with live connectivity status
# Returns comma-separated "name:status" pairs (e.g. "ctx7:connected,remote:failed")
# Caches results for 300s (5 min) per directory
get_configured_mcp_servers_with_status() {
    local search_dir="${1:-${STATUSLINE_CURRENT_DIR:-$(pwd)}}"
    local result=""
    local dir_hash
    dir_hash=$(printf '%s' "$search_dir" | md5sum 2>/dev/null | cut -c1-8) ||
    dir_hash=$(printf '%s' "$search_dir" | md5 -q 2>/dev/null | cut -c1-8) ||
    dir_hash="default"
    local cache_key="mcp_configured_servers_${dir_hash}"

    if [[ "${STATUSLINE_CACHE_LOADED:-}" == "true" ]]; then
        local cached
        cached=$(get_cached_value "$cache_key" "300" 2>/dev/null)
        if [[ -n "$cached" ]]; then
            debug_log "MCP configured servers from cache: $cached" "INFO"
            echo "$cached"
            return 0
        fi
    fi

    local servers
    servers=$(get_configured_mcp_servers "$search_dir")

    if [[ -z "$servers" ]]; then
        return 0
    fi

    while IFS= read -r line; do
        [[ -z "$line" ]] && continue
        local name="${line%%:*}"
        local rest="${line#*:}"
        local command="${rest%%:*}"
        local ssh_host="${rest#*:}"

        local status="configured"
        if [[ "$command" == "ssh" && -n "$ssh_host" ]]; then
            if probe_ssh_server "$ssh_host" "1"; then
                status="connected"
            else
                status="failed"
            fi
        elif command_exists "$command"; then
            status="connected"
        else
            status="failed"
        fi

        if [[ -n "$result" ]]; then
            result="$result,$name:$status"
        else
            result="$name:$status"
        fi
    done <<< "$servers"

    if [[ -n "$result" && "${STATUSLINE_CACHE_LOADED:-}" == "true" ]]; then
        set_cached_value "$cache_key" "$result" 2>/dev/null
    fi

    debug_log "MCP configured servers probed: $result" "INFO"
    echo "$result"
}

# ============================================================================
# PLUGIN DETECTION
# ============================================================================

# Get enabled CC plugins from settings.json, excluding LSP servers
# Returns comma-separated plugin names (e.g. "context7,superpowers,ralph-wiggum")
get_enabled_mcp_plugins() {
    local settings_file="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json"

    if [[ ! -f "$settings_file" ]]; then
        return 0
    fi

    local plugins
    plugins=$(jq -r '
        .enabledPlugins // {} | to_entries[]
        | select(.value == true)
        | .key
        | select(test("-lsp@") | not)
        | split("@") | .[0]
    ' "$settings_file" 2>/dev/null)

    if [[ -z "$plugins" ]]; then
        return 0
    fi

    local result=""
    while IFS= read -r name; do
        [[ -z "$name" ]] && continue
        if [[ -n "$result" ]]; then
            result="$result,$name"
        else
            result="$name"
        fi
    done <<< "$plugins"

    echo "$result"
}

# ============================================================================
# SESSION MCP DETECTION (Transcript Parsing)
# ============================================================================
# Extracts MCP server names from the session transcript JSONL.
# Detects servers like pencil, chrome, slack that aren't in config files.
# Filters out plugin_* (already in Plugin:) and servers in Remote:.

# Get session MCP servers from transcript JSONL
# Returns: comma-separated "name:connected" pairs
get_session_mcp_servers() {
    if [[ -z "${STATUSLINE_INPUT_JSON:-}" ]]; then
        return 0
    fi

    local transcript_path
    transcript_path=$(echo "$STATUSLINE_INPUT_JSON" | jq -r '.transcript_path // empty' 2>/dev/null)

    if [[ -z "$transcript_path" ]]; then
        return 0
    fi

    # Derive project directory from transcript path
    local project_dir
    project_dir=$(dirname "$transcript_path")

    if [[ -z "$project_dir" || ! -d "$project_dir" ]]; then
        return 0
    fi

    # Cache per project directory (shared across sessions, 1 hour TTL)
    local dir_hash
    dir_hash=$(printf '%s' "$project_dir" | md5sum 2>/dev/null | cut -c1-8) ||
    dir_hash=$(printf '%s' "$project_dir" | md5 -q 2>/dev/null | cut -c1-8) ||
    dir_hash="default"
    local cache_key="mcp_session_servers_${dir_hash}"

    if [[ "${STATUSLINE_CACHE_LOADED:-}" == "true" ]]; then
        local cached
        cached=$(get_cached_value "$cache_key" "3600" 2>/dev/null)
        if [[ -n "$cached" ]]; then
            debug_log "MCP session servers from cache: $cached" "INFO"
            echo "$cached"
            return 0
        fi
    fi

    # Scan ALL project transcripts for MCP tool references (not just current session)
    # Tool names like mcp__pencil__batch_design only appear when tools are USED,
    # so we scan all sessions to catch servers used in previous sessions.
    local servers
    servers=$(grep -rohE 'mcp__[a-zA-Z0-9_-]+__[a-zA-Z0-9_-]+' "$project_dir"/*.jsonl 2>/dev/null |
        while IFS= read -r tool; do
            local rest="${tool#mcp__}"
            echo "${rest%%__*}"
        done | sort -u)

    if [[ -z "$servers" ]]; then
        return 0
    fi

    local result=""
    while IFS= read -r name; do
        [[ -z "$name" ]] && continue

        # Skip plugin_* servers (already covered by Plugin: component)
        [[ "$name" == plugin_* ]] && continue

        # Skip servers already in Remote: component
        if [[ -n "${COMPONENT_MCP_SERVERS_DATA:-}" ]]; then
            if [[ ",${COMPONENT_MCP_SERVERS_DATA}," == *",${name}:"* ]]; then
                continue
            fi
        fi

        # Session servers are active (they're in the transcript = tools available)
        if [[ -n "$result" ]]; then
            result="$result,$name:connected"
        else
            result="$name:connected"
        fi
    done <<< "$servers"

    # Cache result
    if [[ -n "$result" && "${STATUSLINE_CACHE_LOADED:-}" == "true" ]]; then
        set_cached_value "$cache_key" "$result" 2>/dev/null
    fi

    debug_log "MCP session servers from transcript: $result" "INFO"
    echo "$result"
}

# ============================================================================
# NAME FORMATTING
# ============================================================================

# Truncate MCP server/plugin name to max length for display
truncate_mcp_name() {
    local name="$1"
    local max_len="${2:-15}"

    if [[ ${#name} -le $max_len ]]; then
        echo "$name"
    else
        echo "${name:0:$max_len}"
    fi
}

# Get only active (connected) MCP servers
get_active_mcp_servers() {
    start_timer "mcp_active_servers"
    
    local all_servers
    all_servers=$(get_all_mcp_servers)
    
    if [[ "$all_servers" == "$CONFIG_MCP_UNKNOWN_MESSAGE" ]] || [[ "$all_servers" == "$CONFIG_MCP_NONE_MESSAGE" ]]; then
        local _discard; _discard=$(end_timer "mcp_active_servers")
        echo "$all_servers"
        return 0
    fi
    
    local active_servers=""
    
    # Filter only connected servers
    local temp_servers="${all_servers}," # Add trailing comma for easier parsing
    local parse_count=0
    local max_servers=50  # Prevent infinite parsing loops
    
    while [[ "$temp_servers" == *","* ]] && [[ $parse_count -lt $max_servers ]]; do
        local server_entry="${temp_servers%%,*}"
        temp_servers="${temp_servers#*,}"
        parse_count=$((parse_count + 1))
        
        # Extract server name and status
        local server_name="${server_entry%:*}"
        local server_status="${server_entry#*:}"
        
        if [[ "$server_status" == "$MCP_STATUS_CONNECTED" ]]; then
            if [[ -z "$active_servers" ]]; then
                active_servers="$server_name"
            else
                active_servers="${active_servers},${server_name}"
            fi
        fi
    done
    
    local active_servers_time
    active_servers_time=$(end_timer "mcp_active_servers")
    debug_log "MCP active servers check completed in ${active_servers_time}s" "INFO"
    
    if [[ -n "$active_servers" ]]; then
        echo "$active_servers"
    else
        echo "$CONFIG_MCP_NONE_MESSAGE"
    fi
}

# ============================================================================
# MCP DISPLAY FORMATTING
# ============================================================================

# Format MCP servers with colors and strikethrough for broken ones
format_mcp_servers() {
    local servers="$1"
    local formatted=""

    if [[ "$servers" == "$CONFIG_MCP_UNKNOWN_MESSAGE" ]] || [[ "$servers" == "$CONFIG_MCP_NONE_MESSAGE" ]]; then
        echo "$servers"
        return
    fi

    # Split servers by comma and process each one
    local temp_servers="${servers}," # Add trailing comma for easier parsing
    local parse_count=0
    local max_servers=50  # Prevent infinite parsing loops
    
    while [[ "$temp_servers" == *","* ]] && [[ $parse_count -lt $max_servers ]]; do
        local server_entry="${temp_servers%%,*}"
        temp_servers="${temp_servers#*,}"
        parse_count=$((parse_count + 1))
        
        # Extract server name and status
        local server_name="${server_entry%:*}"
        local server_status="${server_entry#*:}"

        local formatted_server
        case "$server_status" in
            "$MCP_STATUS_CONNECTED")
                # Green for connected servers
                formatted_server="${CONFIG_BRIGHT_GREEN}${server_name}${CONFIG_RESET}"
                ;;
            "$MCP_STATUS_ERROR")
                # Red with strikethrough for error servers
                formatted_server="${CONFIG_RED}${CONFIG_STRIKETHROUGH}${server_name}${CONFIG_RESET}"
                ;;
            "$MCP_STATUS_DISCONNECTED"|"$MCP_STATUS_UNKNOWN"|*)
                # Red with strikethrough for disconnected/unknown servers
                formatted_server="${CONFIG_RED}${CONFIG_STRIKETHROUGH}${server_name}${CONFIG_RESET}"
                ;;
        esac

        if [[ -z "$formatted" ]]; then
            formatted="$formatted_server"
        else
            formatted="$formatted, $formatted_server"
        fi
    done

    echo "$formatted"
}

# Determine MCP status color and display format
get_mcp_display() {
    local mcp_status="$1"
    
    if [[ "$mcp_status" == "?/?" ]]; then
        echo "31m:MCP:?/?" # Red for error
    elif [[ "$mcp_status" =~ ^([0-9]+)/([0-9]+)$ ]]; then
        local connected="${BASH_REMATCH[1]}"
        local total="${BASH_REMATCH[2]}"

        if [[ "$total" == "0" ]]; then
            # No MCP servers configured - show as dim/gray
            echo "2m:---" # Dim for "no MCP configured"
        elif [[ "$connected" == "$total" ]]; then
            echo "92m:MCP:${mcp_status}" # Bright green for all connected
        else
            echo "33m:MCP:${mcp_status}" # Yellow for partial connection
        fi
    else
        echo "31m:MCP:?/?" # Red for unknown format
    fi
}

# ============================================================================
# MCP HEALTH MONITORING
# ============================================================================

# Check overall MCP system health
get_mcp_health() {
    if ! is_claude_cli_available; then
        echo "no_cli"
        return 1
    fi
    
    local mcp_status
    mcp_status=$(get_mcp_status)
    
    case "$mcp_status" in
        "?/?")
            echo "error"
            ;;
        "0/0")
            echo "no_servers"
            ;;
        *)
            if [[ "$mcp_status" =~ ^([0-9]+)/([0-9]+)$ ]]; then
                local connected="${BASH_REMATCH[1]}"
                local total="${BASH_REMATCH[2]}"
                
                if [[ "$connected" == "$total" ]]; then
                    echo "healthy"
                elif [[ "$connected" -gt 0 ]]; then
                    echo "partial"
                else
                    echo "unhealthy"
                fi
            else
                echo "unknown"
            fi
            ;;
    esac
}

# Get MCP server details (for debugging/troubleshooting)
get_mcp_server_details() {
    local server_name="$1"
    
    if [[ -z "$server_name" ]]; then
        handle_error "Server name required for details" 1 "get_mcp_server_details"
        return 1
    fi
    
    local all_servers
    all_servers=$(get_all_mcp_servers)
    
    # Find the specific server
    local temp_servers="${all_servers},"
    local parse_count=0
    local max_servers=50  # Prevent infinite parsing loops
    
    while [[ "$temp_servers" == *","* ]] && [[ $parse_count -lt $max_servers ]]; do
        local server_entry="${temp_servers%%,*}"
        temp_servers="${temp_servers#*,}"
        parse_count=$((parse_count + 1))
        
        local entry_name="${server_entry%:*}"
        local entry_status="${server_entry#*:}"
        
        if [[ "$entry_name" == "$server_name" ]]; then
            echo "Server: $entry_name"
            echo "Status: $entry_status"
            return 0
        fi
    done
    
    echo "Server '$server_name' not found"
    return 1
}

# ============================================================================
# MCP CACHING (Optional Enhancement)
# ============================================================================

# Cache MCP status for performance (optional)
get_cached_mcp_status() {
    local cache_duration="${1:-120}" # 2 minutes default - MCP disconnections are not that frequent
    
    # Use universal caching system if available
    if [[ "${STATUSLINE_CACHE_LOADED:-}" == "true" ]]; then
        # Generate repository-aware cache key for MCP status
        local cache_key
        cache_key=$(generate_typed_cache_key "mcp_status" "mcp")
        cache_external_command "$cache_key" "$cache_duration" "validate_command_output" bash -c 'get_mcp_status'
    else
        # Fallback to direct execution
        get_mcp_status
    fi
}

# ============================================================================
# MODULE INITIALIZATION
# ============================================================================

# Initialize the MCP module
init_mcp_module() {
    debug_log "MCP monitoring module initialized" "INFO"
    
    # Check if Claude CLI is available
    if ! is_claude_cli_available; then
        handle_warning "Claude CLI not available - MCP monitoring disabled" "init_mcp_module"
        return 1
    fi
    
    return 0
}

# Initialize the module (skip during testing to allow sourcing without side effects)
if [[ "${STATUSLINE_TESTING:-}" != "true" ]]; then
    init_mcp_module
fi

# Export MCP functions
export -f has_native_mcp_data get_native_mcp_servers get_native_mcp_status
export -f is_claude_cli_available execute_mcp_list parse_mcp_server_list
export -f get_mcp_status get_all_mcp_servers get_active_mcp_servers
export -f format_mcp_servers get_mcp_display get_mcp_health
export -f get_mcp_server_details get_cached_mcp_status
export -f get_configured_mcp_servers probe_ssh_server get_configured_mcp_servers_with_status
export -f get_enabled_mcp_plugins truncate_mcp_name get_session_mcp_servers