Skip to main content
Glama

MCP Server for Splunk

Apache 2.0
16
  • Apple
  • Linux
build_and_run.ps1โ€ข42.3 kB
# Build and Run MCP Server for Splunk - Windows PowerShell Version # This script builds the Docker image and runs it with docker-compose, or falls back to local mode param( [switch]$LocalOnly, [switch]$DockerOnly, [switch]$Help ) # Set strict mode for better error handling Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" # Change to the project root directory (parent of scripts) $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $projectRoot = Split-Path -Parent $scriptDir Set-Location $projectRoot # Show help if requested if ($Help) { Write-Host @" MCP Server for Splunk - Build and Run Script (Windows) Usage: .\scripts\build_and_run.ps1 [options] Options: -LocalOnly Force local development mode (bypass Docker) -DockerOnly Force Docker mode (fail if Docker unavailable) -Help Show this help message Examples: .\scripts\build_and_run.ps1 # Auto-detect best mode .\scripts\build_and_run.ps1 -LocalOnly # Use local development mode .\scripts\build_and_run.ps1 -DockerOnly # Use Docker mode only Prerequisites: - Python 3.10+ (for local mode) - uv package manager (auto-installed if missing) - Docker Desktop (for Docker mode) - Node.js/npm (optional, for MCP Inspector) Configuration: - Edit .env file with your Splunk credentials - Or set MCP_SPLUNK_* environment variables "@ exit 0 } Write-Host "๐Ÿš€ Building and Running MCP Server for Splunk (Windows)" -ForegroundColor Cyan Write-Host "=============================================" -ForegroundColor Cyan Write-Host "" Write-Host "๐Ÿ“š Need help with prerequisites? See: docs/getting-started/installation.md" -ForegroundColor Yellow Write-Host "" # Color functions for consistent output function Write-Status { param([string]$Message) Write-Host "[INFO] $Message" -ForegroundColor Blue } function Write-Success { param([string]$Message) Write-Host "[SUCCESS] $Message" -ForegroundColor Green } function Write-Warning { param([string]$Message) Write-Host "[WARNING] $Message" -ForegroundColor Yellow } function Write-Error { param([string]$Message) Write-Host "[ERROR] $Message" -ForegroundColor Red } function Write-Local { param([string]$Message) Write-Host "[LOCAL] $Message" -ForegroundColor Magenta } # Function to ensure logs directory exists function Ensure-LogsDir { if (-not (Test-Path "logs")) { Write-Local "Creating logs directory..." New-Item -ItemType Directory -Path "logs" -Force | Out-Null } } # Function to load environment variables from .env file function Load-EnvFile { if (Test-Path ".env") { Write-Local "Loading environment variables from .env file..." $envVars = @{} $sensitiveVars = @("PASSWORD", "SECRET", "TOKEN") Get-Content ".env" | ForEach-Object { $line = $_.Trim() # Skip empty lines and comments if ($line -eq "" -or $line.StartsWith("#")) { return } # Parse variable assignment if ($line -match "^([A-Za-z_][A-Za-z0-9_]*)=(.*)$") { $varName = $matches[1] $varValue = $matches[2] # Remove surrounding quotes if present $varValue = $varValue -replace '^"(.*)"$', '$1' -replace "^'(.*)'$", '$1' # Set environment variable [Environment]::SetEnvironmentVariable($varName, $varValue, "Process") $envVars[$varName] = $varValue # Only show non-sensitive variables $isSensitive = $sensitiveVars | Where-Object { $varName -like "*$_*" } if ($isSensitive) { Write-Local "Loaded: $varName=***" } else { Write-Local "Loaded: $varName=$varValue" } } } Write-Success "Environment variables loaded from .env file!" # Show summary of important Splunk configuration Write-Host "" Write-Status "๐Ÿ“‹ Splunk Configuration Summary:" Write-Host " ๐ŸŒ Host: $($env:SPLUNK_HOST ?? 'Not set')" Write-Host " ๐Ÿ”Œ Port: $($env:SPLUNK_PORT ?? '8089 (default)')" Write-Host " ๐Ÿ‘ค User: $($env:SPLUNK_USERNAME ?? 'Not set')" # Show last 3 chars of password for verification if ($env:SPLUNK_PASSWORD) { $passDisplay = "***" + $env:SPLUNK_PASSWORD.Substring([Math]::Max(0, $env:SPLUNK_PASSWORD.Length - 3)) Write-Host " ๐Ÿ” Pass: $passDisplay" } else { Write-Host " ๐Ÿ” Pass: Not set" } Write-Host " ๐Ÿ”’ SSL: $($env:SPLUNK_VERIFY_SSL ?? 'Not set')" # Check for alternative MCP_SPLUNK_* variables if ($env:MCP_SPLUNK_HOST -or $env:MCP_SPLUNK_USERNAME -or $env:MCP_SPLUNK_PASSWORD) { Write-Host "" Write-Status "๐Ÿ“‹ Alternative MCP Splunk Configuration Found:" Write-Host " ๐ŸŒ Host: $($env:MCP_SPLUNK_HOST ?? 'Not set')" Write-Host " ๐Ÿ‘ค User: $($env:MCP_SPLUNK_USERNAME ?? 'Not set')" # Show last 3 chars of MCP password for verification if ($env:MCP_SPLUNK_PASSWORD) { $mcpPassDisplay = "***" + $env:MCP_SPLUNK_PASSWORD.Substring([Math]::Max(0, $env:MCP_SPLUNK_PASSWORD.Length - 3)) Write-Host " ๐Ÿ” Pass: $mcpPassDisplay" } else { Write-Host " ๐Ÿ” Pass: Not set" } Write-Local "These MCP_SPLUNK_* variables will override the SPLUNK_* variables in the MCP server." } Write-Host "" } else { Write-Warning "No .env file found. Using system environment variables only." # Check if any Splunk environment variables are set in the system if ($env:SPLUNK_HOST -or $env:MCP_SPLUNK_HOST) { Write-Status "๐Ÿ“‹ System Environment Splunk Configuration:" Write-Host " ๐ŸŒ Host: $($env:SPLUNK_HOST ?? $env:MCP_SPLUNK_HOST ?? 'Not set')" Write-Host " ๐Ÿ‘ค User: $($env:SPLUNK_USERNAME ?? $env:MCP_SPLUNK_USERNAME ?? 'Not set')" # Show last 3 chars of password for verification $sysPassword = $env:SPLUNK_PASSWORD ?? $env:MCP_SPLUNK_PASSWORD if ($sysPassword) { $sysPassDisplay = "***" + $sysPassword.Substring([Math]::Max(0, $sysPassword.Length - 3)) Write-Host " ๐Ÿ” Pass: $sysPassDisplay" } else { Write-Host " ๐Ÿ” Pass: Not set" } } else { Write-Warning "No Splunk configuration found in environment variables." Write-Warning "The MCP server may not be able to connect to Splunk without configuration." } } } # Function to check if uv is installed function Test-UV { try { $null = Get-Command "uv" -ErrorAction Stop return $true } catch { return $false } } # Function to install uv function Install-UV { Write-Status "Installing uv package manager..." try { # Use the official uv installation method for Windows if (Get-Command "curl" -ErrorAction SilentlyContinue) { $installer = Invoke-WebRequest -Uri "https://astral.sh/uv/install.ps1" -UseBasicParsing Invoke-Expression $installer.Content } elseif (Get-Command "winget" -ErrorAction SilentlyContinue) { Write-Status "Using winget to install uv..." winget install --id=astral-sh.uv --source=winget } else { Write-Status "Using pip to install uv..." python -m pip install uv } # Refresh PATH to ensure uv is available $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User") # Verify installation if (Test-UV) { Write-Success "uv installed successfully!" } else { throw "uv installation verification failed" } } catch { Write-Error "Failed to install uv. Please install manually:" Write-Error " Option 1: pip install uv" Write-Error " Option 2: Download from https://astral.sh/uv/" Write-Error " Option 3: winget install astral-sh.uv" Write-Host "" Write-Error "๐Ÿ“š For detailed installation instructions, see:" Write-Error " docs/getting-started/installation.md#-uv-package-manager-installation" exit 1 } } # Function to setup local environment function Setup-LocalEnv { Write-Local "Setting up local development environment..." # Check if uv is available if (-not (Test-UV)) { Write-Warning "uv not found. Installing uv..." Install-UV } # Check if virtual environment and dependencies are installed if (-not (Test-Path ".venv") -or -not (Test-Path ".venv/pyvenv.cfg")) { Write-Local "Creating virtual environment and installing dependencies..." & uv sync --dev if ($LASTEXITCODE -ne 0) { Write-Error "Failed to create virtual environment and install dependencies" exit 1 } } else { Write-Local "Virtual environment exists. Checking if sync is needed..." # Check if uv.lock is newer than .venv (Windows compatible) $uvLockTime = (Get-Item "uv.lock" -ErrorAction SilentlyContinue)?.LastWriteTime $pyprojectTime = (Get-Item "pyproject.toml" -ErrorAction SilentlyContinue)?.LastWriteTime $venvTime = (Get-Item ".venv/pyvenv.cfg" -ErrorAction SilentlyContinue)?.LastWriteTime if (($uvLockTime -and $venvTime -and $uvLockTime -gt $venvTime) -or ($pyprojectTime -and $venvTime -and $pyprojectTime -gt $venvTime)) { Write-Local "Dependencies may be outdated. Running uv sync..." & uv sync --dev if ($LASTEXITCODE -ne 0) { Write-Error "Failed to sync dependencies" exit 1 } } else { Write-Local "Dependencies are up to date." } } # Check if .env file exists if (-not (Test-Path ".env")) { Write-Warning ".env file not found. Creating from env.example..." Copy-Item "env.example" ".env" Write-Warning "Created .env file. You may want to edit it with your Splunk configuration." Write-Warning "For local development, you can also use MCP_SPLUNK_* environment variables." } # Load environment variables from .env file Load-EnvFile Write-Success "Local environment setup complete!" } # Function to find an available port function Find-AvailablePort { param([int]$StartPort = 8001) $maxAttempts = 10 $port = $StartPort for ($i = 0; $i -lt $maxAttempts; $i++) { $portAvailable = $true # First check if anything is listening on the port try { $tcpConnections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue if ($tcpConnections) { $portAvailable = $false } } catch { # If Get-NetTCPConnection isn't available, try TcpListener try { $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Any, $port) $listener.Start() $listener.Stop() # If we got here, port is available return $port } catch { $portAvailable = $false } } if ($portAvailable) { # Double-check by trying to bind try { $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Any, $port) $listener.Start() $listener.Stop() return $port } catch { $portAvailable = $false } } if (-not $portAvailable) { Write-Local "Port $port is in use, trying next port..." } $port++ } # If we can't find a port, return the original Write-Warning "Could not find an available port after $maxAttempts attempts" return $StartPort } # Function to test if a port is listening function Test-PortListening { param([int]$Port) try { $tcpClient = New-Object System.Net.Sockets.TcpClient $tcpClient.ConnectAsync("localhost", $Port).Wait(1000) $isListening = $tcpClient.Connected $tcpClient.Close() return $isListening } catch { return $false } } # Function to run local server function Start-LocalServer { Write-Local "Starting MCP server locally with FastMCP CLI..." # Check if Node.js/npm is available for MCP Inspector $inspectorAvailable = $false $inspectorSupported = $false if (Get-Command "npx" -ErrorAction SilentlyContinue) { $inspectorSupported = $true Write-Local "Node.js/npx detected. MCP Inspector will start after MCP server is running..." } else { Write-Warning "Node.js/npx not found. MCP Inspector will not be available." Write-Warning "To install Node.js: https://nodejs.org/" Write-Host "" Write-Warning "๐Ÿ“š For detailed installation instructions, see:" Write-Warning " docs/getting-started/installation.md#-nodejs-installation-optional---for-mcp-inspector" $inspectorSupported = $false } Write-Host "" Write-Status "Starting MCP server..." # Test if the FastMCP command works first Write-Local "Testing FastMCP installation..." try { & uv run python -c "import fastmcp; print('FastMCP import successful')" if ($LASTEXITCODE -ne 0) { throw "FastMCP import failed" } } catch { Write-Error "FastMCP import failed. Checking installation..." Write-Local "Installing FastMCP..." & uv add fastmcp & uv sync --dev if ($LASTEXITCODE -ne 0) { Write-Error "Failed to install FastMCP" exit 1 } } # Start the server with uv and better error handling Write-Local "Finding available port for MCP server..." # Check for MCP_SERVER_PORT environment variable, default to 8001 $preferredPort = if ($env:MCP_SERVER_PORT) { [int]$env:MCP_SERVER_PORT } else { 8001 } Write-Local "Preferred port from MCP_SERVER_PORT: $preferredPort" # Start from preferred port to avoid conflict with Splunk Web UI (port 8000) $mcpPort = Find-AvailablePort -StartPort $preferredPort if ($mcpPort -ne $preferredPort) { Write-Warning "Port $preferredPort is in use. Using port $mcpPort instead." } else { Write-Local "Using port $mcpPort for MCP server." } Write-Local "Starting MCP server on port $mcpPort..." Write-Local "Command: uv run fastmcp run src/server.py --transport http --port $mcpPort" # Ensure logs directory exists Ensure-LogsDir # Start server in background to check if it starts successfully try { $serverProcess = Start-Process -FilePath "uv" -ArgumentList "run", "fastmcp", "run", "src/server.py", "--transport", "http", "--port", $mcpPort -RedirectStandardOutput "logs/mcp_server.log" -RedirectStandardError "logs/mcp_server_error.log" -PassThru -NoNewWindow # Give server time to start Write-Local "Waiting for MCP server to start..." Start-Sleep -Seconds 3 # Check if the server process is still running if ($serverProcess.HasExited) { Write-Error "MCP server failed to start. Check the logs:" Write-Host "" if (Test-Path "logs/mcp_server.log") { Write-Error "=== MCP Server Log ===" Get-Content "logs/mcp_server.log" | Write-Host Write-Host "" } if (Test-Path "logs/mcp_server_error.log") { Write-Error "=== MCP Server Error Log ===" Get-Content "logs/mcp_server_error.log" | Write-Host Write-Host "" } Write-Error "Troubleshooting steps:" Write-Host "1. Check if src/server.py exists and is valid" Write-Host "2. Verify FastMCP installation: uv run python -c 'import fastmcp'" Write-Host "3. Try running manually: uv run fastmcp run src/server.py --help" Write-Host "4. Check Python environment: uv run python --version" Write-Host "" Write-Error "๐Ÿ“š For prerequisite installation help, see:" Write-Error " docs/getting-started/installation.md" Write-Host "" Write-Error "๐Ÿ”ง Run the prerequisite checker to see what's missing:" Write-Error " .\scripts\check-prerequisites.ps1" Stop-AllProcesses exit 1 } # Check if the chosen port is actually listening Write-Local "Checking if MCP server is listening on port $mcpPort..." $portCheckAttempts = 0 $maxPortAttempts = 5 $serverListening = $false while ($portCheckAttempts -lt $maxPortAttempts) { if (Test-PortListening -Port $mcpPort) { $serverListening = $true break } Start-Sleep -Seconds 2 $portCheckAttempts++ Write-Local "Port check attempt $portCheckAttempts/$maxPortAttempts..." } if ($serverListening) { Write-Success "MCP server is listening on port $mcpPort!" # Also test basic connectivity try { $response = Invoke-WebRequest -Uri "http://localhost:$mcpPort" -TimeoutSec 5 -UseBasicParsing Write-Success "Server responds with HTTP $($response.StatusCode)" } catch { Write-Warning "Server running but HTTP request failed: $_" } # Start MCP Inspector now that the actual port is known if ($inspectorSupported) { Write-Status "Starting MCP Inspector..." if (Test-PortListening -Port 6274) { Write-Warning "MCP Inspector appears to already be running on port 6274" Write-Success "Using existing MCP Inspector instance" $inspectorAvailable = $true } else { # Configure environment for inspector (env vars, not CLI flags) $env:DANGEROUSLY_OMIT_AUTH = "true" $env:MCP_AUTO_OPEN_ENABLED = "false" # Use command-line arguments for more reliable configuration $inspectorUrl = "http://localhost:$mcpPort/mcp/" Write-Local "Configuring MCP Inspector to connect to: $inspectorUrl" Ensure-LogsDir try { $inspectorProcess = Start-Process -FilePath "npx" -ArgumentList "--yes", "@modelcontextprotocol/inspector", "--transport", "streamable-http", "--server-url", $inspectorUrl -RedirectStandardOutput "logs/inspector.log" -RedirectStandardError "logs/inspector_error.log" -PassThru -NoNewWindow Write-Local "Waiting for MCP Inspector to start..." $attempts = 0 $maxAttempts = 10 $inspectorRunning = $false while ($attempts -lt $maxAttempts) { Start-Sleep -Seconds 2 if ($inspectorProcess.HasExited) { Write-Error "MCP Inspector process died. Check logs/inspector.log for details." break } if (Test-PortListening -Port 6274) { $inspectorRunning = $true break } $attempts++ Write-Local "Attempt $attempts/$maxAttempts - waiting for inspector..." } if ($inspectorRunning) { Write-Success "MCP Inspector started successfully on port 6274" $inspectorProcess.Id | Out-File ".inspector_pid" -Encoding ASCII $inspectorAvailable = $true } else { Write-Warning "Failed to start MCP Inspector" if (Test-Path "logs/inspector.log") { Write-Warning "Inspector log (last 10 lines):" Get-Content "logs/inspector.log" -Tail 10 | Write-Host } if (-not $inspectorProcess.HasExited) { $inspectorProcess.Kill() } $inspectorAvailable = $false } } catch { Write-Warning "Failed to start MCP Inspector: $_" $inspectorAvailable = $false } } } } else { Write-Error "MCP server is not listening on port $mcpPort" Write-Error "Server process ID: $($serverProcess.Id)" # Show server logs for debugging if (Test-Path "logs/mcp_server.log") { Write-Error "=== MCP Server Log (last 20 lines) ===" Get-Content "logs/mcp_server.log" -Tail 20 | Write-Host Write-Host "" } Write-Error "Attempting to restart server in foreground for debugging..." $serverProcess.Kill() Start-Sleep -Seconds 2 Write-Local "Running server in foreground mode for debugging..." Write-Local "If this works, there might be a background process issue..." # Try running in foreground (this will block) & uv run fastmcp run src/server.py --transport http --port $mcpPort exit 1 } # Save server PID for cleanup $serverProcess.Id | Out-File ".server_pid" -Encoding ASCII # Show final summary with access points Write-Host "" Write-Success "โœ… MCP Server setup complete!" Write-Host "" Write-Status "๐ŸŽ‰ Local MCP Server Ready!" Write-Host "" Write-Status "๐Ÿ“‹ Access Points:" Write-Host " ๐Ÿ”Œ MCP Server (stdio): Available for MCP clients" Write-Host " ๐Ÿ”Œ MCP Server (HTTP): http://localhost:$mcpPort" if ($inspectorSupported) { Write-Host " ๐Ÿ“Š MCP Inspector: http://localhost:6274" Write-Host "" Write-Status "๐ŸŽฏ Testing Instructions:" Write-Host " 1. Open http://localhost:6274 in your browser" Write-Host " 2. Ensure that Streamable HTTP is set" Write-Host " 3. MCP Inspector is pre-configured to connect to port $mcpPort" Write-Host " 4. Click 'Connect' button at the bottom" Write-Host " 5. Test tools and resources interactively" } else { Write-Host "" Write-Status "๐ŸŽฏ Alternative Testing:" Write-Host " 1. Open https://inspector.mcp.dev/ in your browser" Write-Host " 2. Ensure that Streamable HTTP is set" Write-Host " 3. Enter server URL: http://localhost:$mcpPort/mcp/" Write-Host " 4. Click 'Connect' button at the bottom" Write-Host " 5. Test tools and resources interactively" Write-Host "" Write-Warning "๐Ÿ’ก MCP Inspector Troubleshooting:" Write-Host " โ€ข Check if Node.js is installed: node --version" Write-Host " โ€ข Check inspector logs: Get-Content logs/inspector.log" Write-Host " โ€ข Try manual install: npm install -g @modelcontextprotocol/inspector" Write-Host " โ€ข Manual start: `$env:DANGEROUSLY_OMIT_AUTH='true'; `$env:DEFAULT_TRANSPORT='streamable-http'; `$env:DEFAULT_SERVER_URL='http://localhost:$mcpPort/mcp/'; npx @modelcontextprotocol/inspector" } Write-Host "" Write-Status "๐Ÿ“Š Log Files:" Write-Host " ๐Ÿ“„ MCP Server: logs/mcp_server.log" if ($inspectorSupported) { Write-Host " ๐Ÿ“„ MCP Inspector: logs/inspector.log" } Write-Host "" Write-Status "๐Ÿ›‘ To stop the server:" Write-Host " Press Ctrl+C or run Stop-Process -Name 'uv'" Write-Host "" Write-Local "Server is running in background. Use Ctrl+C to stop." # Monitor both processes try { while ($true) { # Check if server is still running if ($serverProcess.HasExited) { Write-Error "MCP server process died unexpectedly!" if (Test-Path "logs/mcp_server.log") { Write-Error "=== Recent server logs ===" Get-Content "logs/mcp_server.log" -Tail 10 | Write-Host } break } Start-Sleep -Seconds 5 } } finally { Stop-AllProcesses } } catch { Write-Error "Failed to start MCP server: $_" Stop-AllProcesses exit 1 } } # Function to determine if Splunk should be run in Docker function Test-ShouldRunSplunkDocker { # Check if SPLUNK_HOST is not set or is set to 'so1' (our Docker Splunk container) if (-not $env:SPLUNK_HOST -or $env:SPLUNK_HOST -eq "so1") { return $true # run Splunk in Docker } else { return $false # use external Splunk } } # Function to get Docker compose command with profiles function Get-DockerComposeCmd { param([string]$Mode) $baseCmd = "docker-compose" switch ($Mode) { "dev" { $baseCmd = "docker-compose -f docker-compose-dev.yml" } default { $baseCmd = "docker-compose" } } # Add Splunk profile if needed if (Test-ShouldRunSplunkDocker) { if ($Mode -eq "dev") { $baseCmd = "$baseCmd --profile dev --profile splunk" } else { $baseCmd = "$baseCmd --profile splunk" } Write-Local "Including Splunk Enterprise container (SPLUNK_HOST=$($env:SPLUNK_HOST ?? 'not set') indicates local Splunk)" } else { Write-Local "Using external Splunk instance: $env:SPLUNK_HOST" } return $baseCmd } # Function to run Docker setup function Start-DockerSetup { Write-Status "Using Docker deployment mode..." # Check if docker-compose is available if (-not (Get-Command "docker-compose" -ErrorAction SilentlyContinue)) { Write-Error "docker-compose not found. Please install docker-compose or use local mode." Write-Error "To install docker-compose: https://docs.docker.com/compose/install/" Write-Host "" Write-Error "๐Ÿ“š For detailed installation instructions, see:" Write-Error " docs/getting-started/installation.md#-docker-installation-optional---for-full-stack" exit 1 } # If uv is available, ensure uv.lock is up to date for Docker build if (Test-UV) { Write-Status "uv detected. Ensuring uv.lock is up to date for Docker build..." # Check if uv.lock exists and is current $uvLockTime = (Get-Item "uv.lock" -ErrorAction SilentlyContinue)?.LastWriteTime $pyprojectTime = (Get-Item "pyproject.toml" -ErrorAction SilentlyContinue)?.LastWriteTime if (-not (Test-Path "uv.lock") -or ($pyprojectTime -and $uvLockTime -and $pyprojectTime -gt $uvLockTime)) { Write-Status "Updating uv.lock file..." & uv sync --dev if ($LASTEXITCODE -eq 0) { Write-Success "uv.lock updated successfully!" } else { Write-Error "Failed to update uv.lock file" exit 1 } } else { Write-Status "uv.lock is already up to date." } } else { Write-Warning "uv not found. Docker will use existing uv.lock file (if present)." if (-not (Test-Path "uv.lock")) { Write-Warning "No uv.lock file found. Docker build may fail." Write-Warning "Consider installing uv to generate the lock file: https://astral.sh/uv/" } } # Check if .env file exists if (-not (Test-Path ".env")) { Write-Warning ".env file not found. Creating from env.example..." Copy-Item "env.example" ".env" Write-Warning "Created .env file. You may want to edit it with your Splunk configuration." } # Load environment variables from .env file for Docker Compose Load-EnvFile # Ask user for Docker deployment mode Write-Host "" Write-Status "Choose Docker deployment mode:" Write-Host " 1) Production (default) - Optimized for performance, no hot reload" Write-Host " 2) Development - Hot reload enabled, enhanced debugging" Write-Host "" do { $dockerChoice = Read-Host "Enter your choice (1 or 2, default: 1)" if ([string]::IsNullOrEmpty($dockerChoice)) { $dockerChoice = "1" } } while ($dockerChoice -notin @("1", "2")) $dockerMode = "" $serviceName = "mcp-server" switch ($dockerChoice) { "1" { $dockerMode = "prod" Write-Status "Using Production mode (optimized performance)" } "2" { $dockerMode = "dev" $serviceName = "mcp-server-dev" Write-Status "Using Development mode (hot reload enabled)" } } # Get the appropriate docker-compose command $composeCmd = Get-DockerComposeCmd -Mode $dockerMode Write-Status "Building Docker image..." $buildCmd = "$composeCmd build $serviceName" Invoke-Expression $buildCmd if ($LASTEXITCODE -eq 0) { Write-Success "Docker image built successfully!" } else { Write-Error "Failed to build Docker image" exit 1 } Write-Status "Starting services with docker-compose..." $upCmd = "$composeCmd up -d" Invoke-Expression $upCmd if ($LASTEXITCODE -eq 0) { Write-Success "Services started successfully!" } else { Write-Error "Failed to start services" exit 1 } # Wait a moment for services to start Start-Sleep -Seconds 5 Write-Status "Checking service status..." $psCmd = "$composeCmd ps" Invoke-Expression $psCmd Write-Status "Checking MCP server logs..." $logsCmd = "$composeCmd logs $serviceName --tail=20" Invoke-Expression $logsCmd Write-Host "" Write-Success "๐ŸŽ‰ Docker setup complete!" Write-Host "" Write-Status "๐Ÿ“‹ Service URLs:" Write-Host " ๐Ÿ”ง Traefik Dashboard: http://localhost:8080" if (Test-ShouldRunSplunkDocker) { Write-Host " ๐ŸŒ Splunk Web UI: http://localhost:9000 (admin/Chang3d!)" } else { Write-Host " ๐ŸŒ External Splunk: $env:SPLUNK_HOST (configured in .env)" } Write-Host " ๐Ÿ”Œ MCP Server: http://localhost:8001/mcp/" Write-Host " ๐Ÿ“Š MCP Inspector: http://localhost:6274" Write-Host "" Write-Status "๐Ÿ” To check logs:" Write-Host " $composeCmd logs -f $serviceName" Write-Host "" Write-Status "๐Ÿ›‘ To stop all services:" Write-Host " $composeCmd down" if ($dockerMode -eq "dev") { Write-Host "" Write-Status "๐Ÿš€ Development Mode Features:" Write-Host " โ€ข Hot reload enabled - changes sync automatically" Write-Host " โ€ข Enhanced debugging and logging" Write-Host " โ€ข Use: $composeCmd logs -f $serviceName" } } # Function to check if Docker is running function Test-Docker { try { & docker info 2>&1 | Out-Null return ($LASTEXITCODE -eq 0) } catch { return $false } } # Function to stop all processes function Stop-AllProcesses { Write-Local "Shutting down services..." # Kill MCP Server if it was started by this script if (Test-Path ".server_pid") { $serverPid = Get-Content ".server_pid" -ErrorAction SilentlyContinue if ($serverPid) { try { $serverProcess = Get-Process -Id $serverPid -ErrorAction SilentlyContinue if ($serverProcess) { Write-Local "Stopping MCP Server (PID: $serverPid)..." Stop-Process -Id $serverPid -Force -ErrorAction SilentlyContinue } } catch { # Process might already be stopped } } Remove-Item ".server_pid" -ErrorAction SilentlyContinue } # Kill MCP Inspector if it was started by this script if (Test-Path ".inspector_pid") { $inspectorPid = Get-Content ".inspector_pid" -ErrorAction SilentlyContinue if ($inspectorPid) { try { $inspectorProcess = Get-Process -Id $inspectorPid -ErrorAction SilentlyContinue if ($inspectorProcess) { Write-Local "Stopping MCP Inspector (PID: $inspectorPid)..." Stop-Process -Id $inspectorPid -Force -ErrorAction SilentlyContinue } } catch { # Process might already be stopped } } Remove-Item ".inspector_pid" -ErrorAction SilentlyContinue } # Clean up log files Remove-Item "logs/inspector.log", "logs/inspector_error.log", "logs/mcp_server.log", "logs/mcp_server_error.log" -ErrorAction SilentlyContinue Write-Success "Cleanup complete!" } # Set up signal handling for cleanup $null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Stop-AllProcesses } # Function to prompt for Splunk configuration and update .env file function Prompt-SplunkConfig { Write-Host "" Write-Status "๐Ÿ”ง Splunk Configuration Setup" Write-Host "==================================" Write-Host "" # Check if .env file exists, create from example if not if (-not (Test-Path ".env")) { if (Test-Path "env.example") { Write-Local "Creating .env file from env.example..." Copy-Item "env.example" ".env" Write-Success ".env file created from env.example" } else { Write-Error "env.example not found. Cannot create .env file." return $false } } # Read current values from .env file $currentHost = "" $currentPort = "8089" $currentUsername = "admin" $currentPassword = "" if (Test-Path ".env") { $envContent = Get-Content ".env" foreach ($line in $envContent) { if ($line -match "^SPLUNK_HOST=(.+)$") { $currentHost = $matches[1].Trim('"', "'") } elseif ($line -match "^SPLUNK_PORT=(.+)$") { $currentPort = $matches[1].Trim('"', "'") } elseif ($line -match "^SPLUNK_USERNAME=(.+)$") { $currentUsername = $matches[1].Trim('"', "'") } elseif ($line -match "^SPLUNK_PASSWORD=(.+)$") { $currentPassword = $matches[1].Trim('"', "'") } } } Write-Host "Current Splunk configuration:" Write-Host " Host: $($currentHost ? $currentHost : 'Not set')" Write-Host " Port: $currentPort" Write-Host " Username: $currentUsername" Write-Host " Password: $($currentPassword ? '***' : 'Not set')" Write-Host "" # Prompt for new values $newHost = Read-Host "Enter Splunk host/URL (current: $($currentHost ? $currentHost : 'Not set'), press Enter to keep)" $newPort = Read-Host "Enter Splunk port (current: $currentPort, press Enter to keep)" $newUsername = Read-Host "Enter Splunk username (current: $currentUsername, press Enter to keep)" $newPassword = Read-Host "Enter Splunk password (press Enter to keep current)" -AsSecureString # Use new values if provided, otherwise keep current $finalHost = if ($newHost) { $newHost } else { $currentHost } $finalPort = if ($newPort) { $newPort } else { $currentPort } $finalUsername = if ($newUsername) { $newUsername } else { $currentUsername } $finalPassword = if ($newPassword.Length -gt 0) { $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($newPassword) [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) } else { $currentPassword } # Parse URL if provided (strip protocol and extract hostname) if ($newHost) { if ($newHost -match "^https?://(.+)$") { $finalHost = $matches[1] Write-Local "Extracted hostname from URL: $finalHost" # Set SSL verification based on protocol if ($newHost -match "^https://") { $env:SPLUNK_VERIFY_SSL = "true" Write-Local "HTTPS detected - setting SPLUNK_VERIFY_SSL=true" } else { $env:SPLUNK_VERIFY_SSL = "false" Write-Local "HTTP detected - setting SPLUNK_VERIFY_SSL=false" } } } # Validate required fields if (-not $finalHost) { Write-Error "SPLUNK_HOST is required. Please provide a value." return $false } if (-not $finalUsername) { Write-Error "SPLUNK_USERNAME is required. Please provide a value." return $false } if (-not $finalPassword) { Write-Error "SPLUNK_PASSWORD is required. Please provide a value." return $false } # Show final configuration for confirmation Write-Host "" Write-Host "Final Splunk configuration:" Write-Host " Host: $finalHost" Write-Host " Port: $finalPort" Write-Host " Username: $finalUsername" Write-Host " Password: ***" Write-Host "" $confirm = Read-Host "Update .env file with these settings? (y/N)" if ($confirm -match "^[Yy]$") { # Update .env file $tempEnv = ".env.tmp" $envContent = Get-Content ".env" # Process .env file line by line foreach ($line in $envContent) { if ($line -match "^SPLUNK_HOST=") { "SPLUNK_HOST=$finalHost" | Out-File -FilePath $tempEnv -Append -Encoding ASCII } elseif ($line -match "^SPLUNK_PORT=") { "SPLUNK_PORT=$finalPort" | Out-File -FilePath $tempEnv -Append -Encoding ASCII } elseif ($line -match "^SPLUNK_USERNAME=") { "SPLUNK_USERNAME=$finalUsername" | Out-File -FilePath $tempEnv -Append -Encoding ASCII } elseif ($line -match "^SPLUNK_PASSWORD=") { "SPLUNK_PASSWORD=$finalPassword" | Out-File -FilePath $tempEnv -Append -Encoding ASCII } else { $line | Out-File -FilePath $tempEnv -Append -Encoding ASCII } } # Replace original .env with updated version Move-Item $tempEnv ".env" -Force Write-Success ".env file updated successfully!" # Set the new values for current session $env:SPLUNK_HOST = $finalHost $env:SPLUNK_PORT = $finalPort $env:SPLUNK_USERNAME = $finalUsername $env:SPLUNK_PASSWORD = $finalPassword return $true } else { Write-Warning "Configuration update cancelled." return $false } } # Prompt for Splunk configuration before proceeding Prompt-SplunkConfig # Main logic: Check Docker availability and choose deployment method try { Write-Status "Checking available deployment options..." # Handle command line parameters if ($DockerOnly) { if (Test-Docker) { Start-DockerSetup } else { Write-Error "Docker mode requested but Docker is not available" exit 1 } } elseif ($LocalOnly) { Setup-LocalEnv Start-LocalServer } else { # Auto-detect best mode if (Test-Docker) { Write-Success "Docker is available and running." # Ask user preference if both Docker and uv are available if (Test-UV) { Write-Host "" Write-Status "Both Docker and local development options are available." Write-Host "Choose deployment method:" Write-Host " 1) Docker (full stack with Splunk, Traefik, MCP Inspector)" Write-Host " 2) Local (FastMCP server only, lighter weight)" Write-Host "" do { $choice = Read-Host "Enter your choice (1 or 2, default: 1)" if ([string]::IsNullOrEmpty($choice)) { $choice = "1" } } while ($choice -notin @("1", "2")) switch ($choice) { "1" { Start-DockerSetup } "2" { Setup-LocalEnv Start-LocalServer } } } else { # Docker available but no uv, use Docker Start-DockerSetup } } elseif (Test-UV) { # No Docker but uv available, use local Write-Warning "Docker is not available. Setting up local development mode..." Setup-LocalEnv Start-LocalServer } else { # Neither Docker nor uv available Write-Warning "Neither Docker nor uv is available." Write-Host "" Write-Warning "๐Ÿ“š For detailed installation instructions, see:" Write-Warning " docs/getting-started/installation.md" Write-Host "" Write-Warning "๐Ÿ”ง You can also run our prerequisite checker to see what's missing:" Write-Warning " .\scripts\check-prerequisites.ps1" Write-Host "" Write-Status "Attempting to install uv automatically..." Install-UV Setup-LocalEnv Start-LocalServer } } } catch { Write-Error "An error occurred: $_" Stop-AllProcesses exit 1 }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/deslicer/mcp-for-splunk'

If you have feedback or need assistance with the MCP directory API, please join our Discord server