Skip to main content
Glama
foundry-mcp-server.nsi53.3 kB
; Foundry MCP Server Windows Installer ; Built with NSIS (Nullsoft Scriptable Install System) ;-------------------------------- ; Include Modern UI and PowerShell support !include "MUI2.nsh" !include "FileFunc.nsh" !include "Sections.nsh" !include "nsDialogs.nsh" !include "LogicLib.nsh" ; Include inetc plugin for downloading ComfyUI !addplugindir "." ; PowerShell execution macro - fixed for NSIS/PowerShell compatibility !macro PowerShellExecWithOutput command nsExec::ExecToStack 'powershell.exe -inputformat none -NoProfile -ExecutionPolicy Bypass -Command "${command}"' !macroend !define PowerShellExecWithOutput "!insertmacro PowerShellExecWithOutput" ; PowerShell file execution macro !macro PowerShellExecFile filepath parameters nsExec::ExecToStack 'powershell.exe -inputformat none -NoProfile -ExecutionPolicy Bypass -File "${filepath}" ${parameters}' !macroend !define PowerShellExecFile "!insertmacro PowerShellExecFile" ;-------------------------------- ; General Configuration Name "Foundry MCP Server" ; Allow output file to be overridden from command line !ifndef OUTFILE !define OUTFILE "FoundryMCPServer-Setup.exe" !endif OutFile "${OUTFILE}" Unicode True ; Default installation directory InstallDir "$LOCALAPPDATA\FoundryMCPServer" ; Request application privileges (user level, no admin required) RequestExecutionLevel user ; Version information ; Strip 'v' prefix and any suffix (like '-pre', '-alpha', etc.) from VERSION !ifndef VERSION !define VERSION "v0.5.5" !endif ; Process VERSION: remove 'v' prefix and everything after '-' !searchparse /noerrors "${VERSION}" "v" STRIPPED_VERSION !ifndef STRIPPED_VERSION !define STRIPPED_VERSION "${VERSION}" !endif !searchparse /noerrors "${STRIPPED_VERSION}" "" VERSION_BASE "-" !ifndef VERSION_BASE !define VERSION_BASE "${STRIPPED_VERSION}" !endif VIProductVersion "${VERSION_BASE}.0" VIAddVersionKey "ProductName" "Foundry MCP Server" VIAddVersionKey "CompanyName" "Foundry MCP Bridge" VIAddVersionKey "FileDescription" "AI-powered campaign management with map generation for Foundry VTT" VIAddVersionKey "FileVersion" "${VERSION_BASE}.0" VIAddVersionKey "LegalCopyright" "© 2024 Foundry MCP Bridge" ;-------------------------------- ; Interface Configuration !define MUI_ABORTWARNING !define MUI_ICON "icon.ico" !define MUI_UNICON "icon.ico" ; Welcome page !define MUI_WELCOMEPAGE_TITLE "Foundry MCP Server Setup" !define MUI_WELCOMEPAGE_TEXT "This wizard will install Foundry MCP Server, which enables AI-powered campaign management and battlemap generation for Foundry VTT using Claude Desktop.$\r$\n$\r$\nOptionally install the Foundry MCP Bridge module and ComfyUI for AI-powered map generation directly to your system for seamless setup.$\r$\n$\r$\nClick Next to continue." ; Directory page !define MUI_DIRECTORYPAGE_TEXT_TOP "Choose the folder where you want to install Foundry MCP Server." ; Components page !define MUI_COMPONENTSPAGE_TEXT_TOP "Select the components you want to install:" !define MUI_COMPONENTSPAGE_TEXT_COMPLIST "Check the components you want to install and uncheck the components you don't want to install. Click Next to continue." ; Finish page (will be customized based on what was installed) !define MUI_FINISHPAGE_TITLE "Installation Complete" !define MUI_FINISHPAGE_TEXT_NOREBOOTSUPPORT !define MUI_FINISHPAGE_TEXT "Thank you for installing Foundry MCP Server!$\r$\n$\r$\nNext steps:$\r$\n$\r$\n1. Restart Claude Desktop$\r$\n2. Launch Foundry VTT$\r$\n$\r$\nIf the Foundry module was installed, it will be available in your modules list. Otherwise, install the MCP Bridge module manually.$\r$\n$\r$\nFor support and documentation, visit our GitHub repository." !define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN_TEXT "Open Foundry VTT MCP GitHub" !define MUI_FINISHPAGE_RUN_FUNCTION "OpenGitHub" ;-------------------------------- ; Pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_COMPONENTS ; Custom GPU Selection Page Page custom GPUSelectionCreate GPUSelectionLeave !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ; Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ; Global Variables Var FoundryPath Var ClaudeConfigPath Var FoundryDetectionResult Var ComfyUIDownloadURL Var ComfyUIDownloadName Var GPUType Var AutoDetectionResult Var InstallationSuccess ; Custom GPU selection page variables Var Dialog Var Label1 Var Label2 Var Label3 Var RadioButton1 Var RadioButton2 Var RadioButton3 Var RadioButton4 Var DescriptionBox ; Uninstaller Variables Var un.FoundryPath Var un.ClaudeConfigPath ;-------------------------------- ; Initialization Function Function .onInit ; Initialize installation success flag StrCpy $InstallationSuccess "false" ; Set Foundry module section as checked by default !insertmacro SelectSection SecFoundryModule FunctionEnd Function DetectFoundryInstallation ; Initialize variables StrCpy $FoundryPath "" StrCpy $FoundryDetectionResult "" ; Check if user has Claude Desktop (good sign they'll want this integration) StrCpy $ClaudeConfigPath "$APPDATA\Claude\claude_desktop_config.json" IfFileExists "$ClaudeConfigPath" claude_detected no_claude claude_detected: DetailPrint "Claude Desktop detected - looking for Foundry VTT installation..." StrCpy $FoundryDetectionResult "Claude Desktop found" Goto check_foundry_paths no_claude: DetailPrint "Claude Desktop not detected - checking for Foundry VTT anyway..." StrCpy $FoundryDetectionResult "No Claude Desktop" check_foundry_paths: ; Try primary location first StrCpy $FoundryPath "$LOCALAPPDATA\FoundryVTT\Data\modules" IfFileExists "$FoundryPath" foundry_found DetailPrint "Primary Foundry path not found: $FoundryPath" ; Try secondary location StrCpy $FoundryPath "$APPDATA\FoundryVTT\Data\modules" IfFileExists "$FoundryPath" foundry_found DetailPrint "Secondary Foundry path not found: $FoundryPath" ; Check environment variable ReadEnvStr $0 "FOUNDRY_VTT_DATA_PATH" StrCmp $0 "" check_manual StrCpy $FoundryPath "$0\Data\modules" IfFileExists "$FoundryPath" foundry_found DetailPrint "Environment variable path not found: $FoundryPath" check_manual: ; If all else fails, show folder browser MessageBox MB_YESNO "Foundry VTT not detected automatically.$\r$\n$\r$\nWould you like to browse for your Foundry User Data folder?$\r$\n$\r$\n(Usually located at: $LOCALAPPDATA\FoundryVTT)" IDYES browse_for_foundry IDNO skip_module browse_for_foundry: nsDialogs::SelectFolderDialog "Select Foundry VTT User Data Folder (containing Data subfolder)" "$LOCALAPPDATA" Pop $0 StrCmp $0 CANCEL skip_module ; Validate selection has Data\modules subfolder StrCpy $FoundryPath "$0\Data\modules" IfFileExists "$FoundryPath" foundry_found ; Try alternative - maybe they selected the Data folder directly StrCpy $FoundryPath "$0\modules" IfFileExists "$FoundryPath" foundry_found ; Final error if invalid selection MessageBox MB_ICONSTOP "Selected folder does not contain a valid Foundry VTT Data structure.$\r$\n$\r$\nExpected: [Selected Folder]\Data\modules\$\r$\n$\r$\nModule installation cancelled." Goto skip_module skip_module: DetailPrint "Foundry module installation will be skipped" StrCpy $FoundryPath "" Return foundry_found: DetailPrint "Foundry VTT installation detected at: $FoundryPath" StrCpy $FoundryDetectionResult "$FoundryDetectionResult; Foundry found at $FoundryPath" FunctionEnd ;-------------------------------- ; Helper Functions Function OpenGitHub ExecShell "open" "https://github.com/adambdooley/foundry-vtt-mcp" FunctionEnd Function DownloadComfyUIModels ; Download essential models for battlemap generation DetailPrint "Downloading essential AI models for map generation..." DetailPrint "This may take several minutes for large model files..." ; Create models directory structure CreateDirectory "$INSTDIR\ComfyUI\ComfyUI\models\checkpoints" CreateDirectory "$INSTDIR\ComfyUI\ComfyUI\models\vae" CreateDirectory "$INSTDIR\ComfyUI\ComfyUI\models\configs" CreateDirectory "$INSTDIR\ComfyUI\ComfyUI\models\loras" ; Create output directory for generated images CreateDirectory "$INSTDIR\ComfyUI\ComfyUI\output" ; Download YAML config file first (essential for proper checkpoint loading) DetailPrint "Downloading D&D Battlemaps YAML config file..." inetc::get /SILENT \ "https://huggingface.co/AdamDooley/dnd-battlemaps-sdxl-1.0-mirror/resolve/main/dDBattlemapsSDXL10_upscaleV10.yaml" \ "$INSTDIR\ComfyUI\ComfyUI\models\configs\dDBattlemapsSDXL10_upscaleV10.yaml" /end Pop $0 StrCmp $0 "OK" config_success config_failed config_failed: DetailPrint "YAML config download failed: $0" MessageBox MB_ICONEXCLAMATION|MB_OK "YAML config download failed: $0$\r$\n$\r$\nYou can manually download it later from HuggingFace." Goto download_sdxl config_success: DetailPrint "YAML config downloaded successfully" download_sdxl: ; Download SDXL Base model (essential for image generation) DetailPrint "Downloading SDXL Base model (~6.5GB)... (running silently)" ; Download SDXL Base model using inetc plugin inetc::get /SILENT \ "https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors" \ "$INSTDIR\ComfyUI\ComfyUI\models\checkpoints\sd_xl_base_1.0.safetensors" /end Pop $0 StrCmp $0 "OK" sdxl_success sdxl_failed sdxl_failed: DetailPrint "SDXL Base model download failed: $0" MessageBox MB_ICONEXCLAMATION|MB_OK "SDXL Base model download failed: $0$\r$\n$\r$\nYou can manually download it later from HuggingFace." Goto download_vae sdxl_success: DetailPrint "SDXL Base model downloaded successfully" download_vae: ; Download SDXL VAE (required for proper image decoding) DetailPrint "Downloading SDXL VAE (~335MB)... (running silently)" ; Download SDXL VAE using inetc plugin inetc::get /SILENT \ "https://huggingface.co/stabilityai/sdxl-vae/resolve/main/sdxl_vae.safetensors" \ "$INSTDIR\ComfyUI\ComfyUI\models\vae\sdxl_vae.safetensors" /end Pop $1 StrCmp $1 "OK" vae_success vae_failed vae_failed: DetailPrint "SDXL VAE download failed: $1" MessageBox MB_ICONEXCLAMATION|MB_OK "SDXL VAE download failed: $1$\r$\n$\r$\nYou can manually download it later from HuggingFace." Goto download_dnd_checkpoint vae_success: DetailPrint "SDXL VAE downloaded successfully" Goto download_dnd_checkpoint download_dnd_checkpoint: DetailPrint "Preparing D&D Battlemaps SDXL Upscale checkpoint (~6.5GB)..." IfFileExists "$INSTDIR\ComfyUI\ComfyUI\models\checkpoints\dDBattlemapsSDXL10_upscaleV10.safetensors" dnd_checkpoint_already_present dnd_checkpoint_fetch dnd_checkpoint_already_present: DetailPrint "D&D Battlemaps checkpoint already present; skipping download" Goto models_complete dnd_checkpoint_fetch: DetailPrint "Downloading D&D Battlemaps SDXL Upscale checkpoint (~6.5GB)... (running silently)" inetc::get /SILENT \ "https://huggingface.co/AdamDooley/dnd-battlemaps-sdxl-1.0-mirror/resolve/main/dDBattlemapsSDXL10_upscaleV10.safetensors" \ "$INSTDIR\ComfyUI\ComfyUI\models\checkpoints\dDBattlemapsSDXL10_upscaleV10.safetensors" /end Pop $2 StrCmp $2 "OK" dnd_checkpoint_success dnd_checkpoint_failed dnd_checkpoint_failed: DetailPrint "D&D Battlemaps checkpoint download failed: $2" MessageBox MB_ICONEXCLAMATION|MB_RETRYCANCEL "Failed to download the D&D Battlemaps checkpoint: $2$\r$\n$\r$\nDo you want to retry now?" IDRETRY dnd_checkpoint_retry IDCANCEL dnd_checkpoint_skipped dnd_checkpoint_retry: DetailPrint "Retrying D&D Battlemaps checkpoint download... (running silently)" inetc::get /SILENT \ "https://huggingface.co/AdamDooley/dnd-battlemaps-sdxl-1.0-mirror/resolve/main/dDBattlemapsSDXL10_upscaleV10.safetensors" \ "$INSTDIR\ComfyUI\ComfyUI\models\checkpoints\dDBattlemapsSDXL10_upscaleV10.safetensors" /end Pop $2 StrCmp $2 "OK" dnd_checkpoint_success dnd_checkpoint_final_failed dnd_checkpoint_final_failed: DetailPrint "D&D Battlemaps checkpoint download failed again: $2" MessageBox MB_ICONEXCLAMATION|MB_OK "D&D Battlemaps checkpoint download failed: $2$\r$\n$\r$\nYou can manually download it later from HuggingFace:$\r$\nhttps://huggingface.co/AdamDooley/dnd-battlemaps-sdxl-1.0-mirror/resolve/main/dDBattlemapsSDXL10_upscaleV10.safetensors" Goto dnd_checkpoint_skipped dnd_checkpoint_skipped: DetailPrint "Skipping D&D Battlemaps checkpoint download. You can install it manually later." Goto models_complete dnd_checkpoint_success: DetailPrint "D&D Battlemaps checkpoint downloaded successfully" ; Download D&D Battlemaps license file for compliance DetailPrint "Downloading D&D Battlemaps license file..." inetc::get /SILENT \ "https://huggingface.co/AdamDooley/dnd-battlemaps-sdxl-1.0-mirror/resolve/main/LICENSE.txt" \ "$INSTDIR\ComfyUI\ComfyUI\models\checkpoints\dDBattlemapsSDXL10_LICENSE.txt" /end Pop $3 StrCmp $3 "OK" dnd_license_success dnd_license_failed dnd_license_failed: DetailPrint "D&D Battlemaps license download failed: $3 (non-critical)" Goto models_complete dnd_license_success: DetailPrint "D&D Battlemaps license downloaded successfully" Goto models_complete models_complete: DetailPrint "Model downloads completed" DetailPrint "Note: Additional checkpoints or LoRA models for specific map styles can be downloaded manually" FunctionEnd Function TrimTrailingCRLF Exch $0 Push $1 trim_loop: StrCpy $1 $0 1 -1 StrCmp $1 "$\r" trim_remove StrCmp $1 "$\n" trim_remove StrCmp $1 "" trim_done Goto trim_done trim_remove: StrCpy $0 $0 -1 Goto trim_loop trim_done: Pop $1 Exch $0 FunctionEnd Function DetectGPUHardware ; Detect NVIDIA GPU for CUDA PyTorch installation DetailPrint "Detecting GPU hardware for PyTorch optimization..." StrCpy $0 "$TEMP\detect-gpu.ps1" StrCpy $1 "$TEMP\gpu-result.txt" ; Create PowerShell script for GPU detection (simplified) FileOpen $2 $0 w FileWrite $2 "param([string]`$$outPath)`r`n" FileWrite $2 "$$ProgressPreference = 'SilentlyContinue'`r`n" FileWrite $2 "$$result = 'cpu'`r`n" FileWrite $2 "`r`n" FileWrite $2 "# Try nvidia-smi first`r`n" FileWrite $2 "$$nvidiaSmiPaths = @('C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe', 'C:\Windows\System32\nvidia-smi.exe')`r`n" FileWrite $2 "foreach ($$smiPath in $$nvidiaSmiPaths) {`r`n" FileWrite $2 " if (Test-Path $$smiPath) {`r`n" FileWrite $2 " try {`r`n" FileWrite $2 " $$smiOutput = & $$smiPath --query-gpu=name --format=csv,noheader,nounits 2>$$null`r`n" FileWrite $2 " if ($$LASTEXITCODE -eq 0 -and $$smiOutput) {`r`n" FileWrite $2 " $$result = 'cuda'`r`n" FileWrite $2 " break`r`n" FileWrite $2 " }`r`n" FileWrite $2 " } catch { }`r`n" FileWrite $2 " }`r`n" FileWrite $2 "}`r`n" FileWrite $2 "`r`n" FileWrite $2 "# Try DriverStore if not found`r`n" FileWrite $2 "if ($$result -eq 'cpu') {`r`n" FileWrite $2 " $$driverStorePath = 'C:\Windows\System32\DriverStore\FileRepository'`r`n" FileWrite $2 " if (Test-Path $$driverStorePath) {`r`n" FileWrite $2 " $$foundSmi = Get-ChildItem -Path $$driverStorePath -Recurse -Name 'nvidia-smi.exe' -ErrorAction SilentlyContinue | Select-Object -First 1`r`n" FileWrite $2 " if ($$foundSmi) {`r`n" FileWrite $2 " $$fullPath = Join-Path $$driverStorePath $$foundSmi`r`n" FileWrite $2 " try {`r`n" FileWrite $2 " $$smiOutput = & $$fullPath --query-gpu=name --format=csv,noheader,nounits 2>$$null`r`n" FileWrite $2 " if ($$LASTEXITCODE -eq 0 -and $$smiOutput) {`r`n" FileWrite $2 " $$result = 'cuda'`r`n" FileWrite $2 " }`r`n" FileWrite $2 " } catch { }`r`n" FileWrite $2 " }`r`n" FileWrite $2 " }`r`n" FileWrite $2 "}`r`n" FileWrite $2 "`r`n" FileWrite $2 "# Fallback to WMI`r`n" FileWrite $2 "if ($$result -eq 'cpu') {`r`n" FileWrite $2 " $$gpuCards = Get-WmiObject -Class Win32_VideoController -ErrorAction SilentlyContinue`r`n" FileWrite $2 " if ($$gpuCards) {`r`n" FileWrite $2 " foreach ($$gpu in $$gpuCards) {`r`n" FileWrite $2 " if ($$gpu.Name -and $$gpu.Name.ToLower() -match 'nvidia|geforce|rtx|gtx|quadro|tesla|titan') {`r`n" FileWrite $2 " $$result = 'cuda'`r`n" FileWrite $2 " break`r`n" FileWrite $2 " }`r`n" FileWrite $2 " }`r`n" FileWrite $2 " }`r`n" FileWrite $2 "}`r`n" FileWrite $2 "`r`n" FileWrite $2 "[IO.File]::WriteAllText($$outPath, $$result)`r`n" FileClose $2 ; Execute GPU detection script ${PowerShellExecFile} "$TEMP\detect-gpu.ps1" "$1" Pop $3 Pop $4 ; Clean up script Delete "$TEMP\detect-gpu.ps1" ; Read result StrCpy $5 "cuda12" ; default to CUDA 12.1 (no CPU fallback) IfFileExists "$1" 0 gpu_detection_done FileOpen $2 "$1" r FileRead $2 $5 FileClose $2 Delete "$1" ; Trim result Push $5 Call TrimTrailingCRLF Pop $5 StrCmp $5 "cuda" gpu_cuda_detected gpu_detection_done gpu_cuda_detected: DetailPrint "GPU detected via auto-detection" StrCpy $6 "cuda12" ; Default to CUDA 12.1 for detected GPUs Goto gpu_detection_done gpu_detection_done: ; Store result in global variable for use in ComfyUI installation StrCpy $GPUType "cuda12" ; Always default to CUDA 12.1 StrCpy $AutoDetectionResult "cuda12" ; Store for GPU selection page FunctionEnd Function GPUSelectionCreate ; Only show GPU selection page if ComfyUI component is selected SectionGetFlags 2 $0 ; SecComfyUI is section index 2 IntOp $0 $0 & ${SF_SELECTED} IntCmp $0 ${SF_SELECTED} show_page skip_page skip_page skip_page: ; Skip this page, use auto-detection result StrCpy $GPUType $AutoDetectionResult Abort show_page: ; Try auto-detection first (but don't fail installation if it fails) Call DetectGPUHardware ; Create custom dialog nsDialogs::Create 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} ; Title ${NSD_CreateLabel} 0 10u 100% 12u "GPU Configuration for AI Map Generation" Pop $Label1 ; Description ${NSD_CreateLabel} 0 25u 100% 24u "ComfyUI requires GPU acceleration for map generation (minimum 8GB VRAM required). Choose your GPU type for optimal PyTorch installation:" Pop $Label2 ; VRAM requirement warning ${NSD_CreateLabel} 0 45u 100% 12u "Requirements: NVIDIA/AMD/Intel GPU with at least 8GB VRAM" Pop $Label3 ; Radio buttons for different GPU types ${NSD_CreateRadioButton} 10u 65u 100% 12u "&NVIDIA CUDA 12.1 (RTX 30/40 series, RTX 4090, etc.)" Pop $RadioButton1 ${NSD_CreateRadioButton} 10u 80u 100% 12u "N&VIDIA CUDA 11.8 (GTX 10/20 series, older NVIDIA GPUs)" Pop $RadioButton2 ${NSD_CreateRadioButton} 10u 95u 100% 12u "&AMD ROCm (Radeon RX 6000/7000 series)" Pop $RadioButton3 ${NSD_CreateRadioButton} 10u 110u 100% 12u "&Intel Arc (Arc A-series GPUs)" Pop $RadioButton4 ; Default to CUDA 12.1 (most common) ${NSD_Check} $RadioButton1 ; Info box ${NSD_CreateText} 0 130u 100% 20u "Note: ComfyUI requires ~14GB space and 8GB+ VRAM." Pop $DescriptionBox SendMessage $DescriptionBox ${EM_SETREADONLY} 1 0 nsDialogs::Show FunctionEnd Function GPUSelectionLeave ; Only process if this page was shown SectionGetFlags 2 $0 ; SecComfyUI is section index 2 IntOp $0 $0 & ${SF_SELECTED} IntCmp $0 ${SF_SELECTED} process_selection skip_processing skip_processing skip_processing: Return process_selection: ; Get radio button states ${NSD_GetState} $RadioButton1 $0 ${NSD_GetState} $RadioButton2 $1 ${NSD_GetState} $RadioButton3 $2 ${NSD_GetState} $RadioButton4 $3 ; Set GPU type based on selection ${If} $0 == ${BST_CHECKED} StrCpy $GPUType "cuda12" ; NVIDIA CUDA 12.1 DetailPrint "User selected: NVIDIA CUDA 12.1 for PyTorch installation" ${ElseIf} $1 == ${BST_CHECKED} StrCpy $GPUType "cuda11" ; NVIDIA CUDA 11.8 DetailPrint "User selected: NVIDIA CUDA 11.8 for PyTorch installation" ${ElseIf} $2 == ${BST_CHECKED} StrCpy $GPUType "rocm" ; AMD ROCm DetailPrint "User selected: AMD ROCm for PyTorch installation" ${ElseIf} $3 == ${BST_CHECKED} StrCpy $GPUType "intel" ; Intel Arc DetailPrint "User selected: Intel Arc GPU for PyTorch installation" ${Else} ; Default to CUDA 12.1 if no selection StrCpy $GPUType "cuda12" DetailPrint "No selection made, defaulting to NVIDIA CUDA 12.1" ${EndIf} FunctionEnd Function ResolveComfyUIDownload DetailPrint "Resolving latest ComfyUI portable build..." StrCpy $ComfyUIDownloadURL "" StrCpy $ComfyUIDownloadName "" StrCpy $0 "$TEMP\resolve-comfyui.ps1" StrCpy $1 "$TEMP\comfyui-download.txt" FileOpen $2 $0 w FileWrite $2 "param([string]`$$outPath)`r`n" FileWrite $2 "$$ProgressPreference = 'SilentlyContinue'`r`n" FileWrite $2 "$$headers = @{ 'User-Agent' = 'FoundryMCPInstaller' }`r`n" FileWrite $2 "try {`r`n" FileWrite $2 " $$release = Invoke-RestMethod -Uri 'https://api.github.com/repos/comfyanonymous/ComfyUI/releases/latest' -Headers $$headers`r`n" FileWrite $2 " $$asset = $$release.assets | Where-Object { $$_.name -like 'ComfyUI_windows_portable*.7z' } | Sort-Object -Property name | Select-Object -First 1`r`n" FileWrite $2 " if (-not $$asset) { throw 'No suitable asset found'; }`r`n" FileWrite $2 " [IO.File]::WriteAllLines($$outPath, @($$asset.browser_download_url, $$asset.name))`r`n" FileWrite $2 " exit 0`r`n" FileWrite $2 "} catch {`r`n" FileWrite $2 " [IO.File]::WriteAllText($$outPath, $$_.Exception.Message)`r`n" FileWrite $2 " exit 1`r`n" FileWrite $2 "}`r`n" FileClose $2 DetailPrint "Executing PowerShell script to resolve ComfyUI download URL..." DetailPrint "Script path: $TEMP\resolve-comfyui.ps1" DetailPrint "Output file: $1" nsExec::ExecToStack 'powershell.exe -inputformat none -NoProfile -ExecutionPolicy Bypass -File "$TEMP\resolve-comfyui.ps1" "$1"' Pop $3 Pop $4 DetailPrint "PowerShell exit code: $3" DetailPrint "PowerShell output: $4" Delete "$TEMP\resolve-comfyui.ps1" IntCmp $3 0 resolve_ok resolve_fail resolve_fail resolve_ok: DetailPrint "PowerShell succeeded, checking output file..." IfFileExists "$1" file_exists file_missing file_missing: DetailPrint "Output file not found: $1" Goto resolve_fail file_exists: DetailPrint "Output file found, reading content..." FileOpen $2 "$1" r IntCmp $2 0 file_open_failed file_opened file_opened file_open_failed: DetailPrint "Failed to open output file: $1" Goto resolve_fail file_opened: FileRead $2 $ComfyUIDownloadURL FileRead $2 $ComfyUIDownloadName FileClose $2 Delete "$1" Push $ComfyUIDownloadURL Call TrimTrailingCRLF Pop $ComfyUIDownloadURL Push $ComfyUIDownloadName Call TrimTrailingCRLF Pop $ComfyUIDownloadName DetailPrint "Raw URL: $ComfyUIDownloadURL" DetailPrint "Raw Name: $ComfyUIDownloadName" StrCmp $ComfyUIDownloadURL "" resolve_fail DetailPrint "ComfyUI asset resolved: $ComfyUIDownloadName" Return resolve_fail: Delete "$1" DetailPrint "Failed to resolve ComfyUI release automatically" DetailPrint "PowerShell output: $4" DetailPrint "Using fallback to known working ComfyUI v0.3.60 release..." StrCpy $ComfyUIDownloadURL "https://github.com/comfyanonymous/ComfyUI/releases/download/v0.3.60/ComfyUI_windows_portable_nvidia.7z" StrCpy $ComfyUIDownloadName "ComfyUI_windows_portable_nvidia.7z" DetailPrint "Fallback ComfyUI asset: $ComfyUIDownloadName" Return FunctionEnd Function .onGUIEnd ; Simply mark installation as successful if registry entry exists ; No popup dialogs - information is shown on the finish page instead ReadRegStr $0 HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "DisplayName" StrCmp $0 "" installation_failed installation_success installation_success: StrCpy $InstallationSuccess "true" Return installation_failed: ; Installation was cancelled or failed - don't set success flag Return FunctionEnd Function UpdateClaudeConfig ; Configure Claude Desktop using PowerShell script DetailPrint "Configuring Claude Desktop..." ; First test if PowerShell is available DetailPrint "Testing PowerShell availability..." ${PowerShellExecWithOutput} 'Write-Host "PowerShell OK"' Pop $0 ; Exit code Pop $1 ; Output IntCmp $0 0 powershell_ok powershell_failed powershell_failed powershell_failed: DetailPrint "PowerShell test failed (exit code: $0)" MessageBox MB_ICONEXCLAMATION|MB_OK "PowerShell Not Available$\r$\n$\r$\nFoundry MCP Server installed successfully, but PowerShell is required for automatic Claude Desktop configuration.$\r$\n$\r$\n- See manual setup guide in Start Menu$\r$\n- Configure Claude Desktop manually$\r$\n- Contact support if PowerShell should be available" Goto config_done powershell_ok: DetailPrint "PowerShell available, executing configuration script..." ; Execute PowerShell script with installation directory as parameter ${PowerShellExecFile} "$INSTDIR\configure-claude.ps1" '"-InstallDir \"$INSTDIR\""' Pop $0 ; Exit code Pop $1 ; Output/Error messages ; Check if PowerShell script succeeded IntCmp $0 0 config_success config_failed config_failed config_failed: DetailPrint "Direct PowerShell execution failed (exit code: $0)" DetailPrint "PowerShell output: $1" ; Try batch file fallback method DetailPrint "Attempting batch file fallback method..." nsExec::ExecToStack '"$INSTDIR\configure-claude-wrapper.bat" "$INSTDIR"' Pop $5 ; Exit code from batch Pop $6 ; Output from batch IntCmp $5 0 batch_success batch_failed batch_failed batch_success: DetailPrint "Batch fallback method succeeded" DetailPrint "Batch output: $6" Goto config_success batch_failed: DetailPrint "Batch fallback method also failed (exit code: $5)" DetailPrint "Batch output: $6" ; Extract useful error message from PowerShell output StrLen $2 "$1" IntCmp $2 0 no_output has_output has_output no_output: StrCpy $3 "No error details available" Goto show_error has_output: ; Truncate long output for message box (first 200 chars) StrLen $4 "$1" IntCmp $4 200 show_full truncate_output show_full truncate_output: StrCpy $3 "$1" 200 StrCpy $3 "$3..." Goto show_error show_full: StrCpy $3 "$1" show_error: ; Extract the first line of the error for a cleaner display StrCpy $7 $3 80 ; First 80 characters StrCmp $3 $7 short_error 0 StrCpy $7 "$7..." short_error: ${If} $InstallationSuccess == "true" MessageBox MB_ICONEXCLAMATION|MB_OK "Claude Desktop Configuration Failed$\r$\n$\r$\nError: $7$\r$\n$\r$\nFoundry MCP Server installed successfully, but Claude Desktop configuration could not be completed automatically.$\r$\n$\r$\n- Check detailed error log: %TEMP%\foundry-mcp-claude-config.log$\r$\n- See manual setup guide in Start Menu$\r$\n- Restart Claude Desktop after manual configuration" ${Else} MessageBox MB_ICONEXCLAMATION|MB_OK "Claude Desktop Configuration Failed$\r$\n$\r$\nError: $7$\r$\n$\r$\nInstallation was not completed successfully.$\r$\n$\r$\n- Check detailed error log: %TEMP%\foundry-mcp-claude-config.log$\r$\n- Try running the installer again" ${EndIf} Goto config_done config_success: DetailPrint "Claude Desktop configured successfully" config_done: FunctionEnd ;-------------------------------- ; Installer Sections Section "Foundry MCP Server" SecMain SectionIn RO ; Read-only section (required) ; Set estimated size: Node.js runtime + MCP server + shared components (~32MB) SectionSetSize ${SecMain} 32768 ; Set output path SetOutPath $INSTDIR ; Install Node.js runtime DetailPrint "Installing Node.js runtime..." File /r "node\" File "node.exe" ; Install MCP Server files DetailPrint "Installing MCP Server..." SetOutPath "$INSTDIR\foundry-mcp-server" File /r "foundry-mcp-server\*" SetOutPath "$INSTDIR" ; Install documentation File "README.txt" File "LICENSE.txt" ; Install icon for uninstaller File "icon.ico" ; Install PowerShell configuration script and batch wrapper File "configure-claude.ps1" File "configure-claude-wrapper.bat" ; Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" ; Create Start Menu shortcuts (minimal set to avoid confusion) CreateDirectory "$SMPROGRAMS\Foundry MCP Server" CreateShortcut "$SMPROGRAMS\Foundry MCP Server\Uninstall.lnk" "$INSTDIR\Uninstall.exe" ; Add to Windows Programs list WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "DisplayName" "Foundry MCP Server" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "UninstallString" "$INSTDIR\Uninstall.exe" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "DisplayIcon" "$INSTDIR\icon.ico" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "Publisher" "Foundry MCP Bridge" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "DisplayVersion" "0.5.0" WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "NoModify" 1 WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" "NoRepair" 1 ; Create utility scripts DetailPrint "Creating utility scripts..." ; Start server script FileOpen $0 "$INSTDIR\start-server.bat" w FileWrite $0 '@echo off$\r$\n' FileWrite $0 'echo Starting Foundry MCP Server...$\r$\n' FileWrite $0 'cd /d "$INSTDIR"$\r$\n' FileWrite $0 '"$INSTDIR\node.exe" "$INSTDIR\foundry-mcp-server\packages\mcp-server\dist\index.cjs"$\r$\n' FileWrite $0 'pause$\r$\n' FileClose $0 ; Test connection script FileOpen $0 "$INSTDIR\test-connection.bat" w FileWrite $0 '@echo off$\r$\n' FileWrite $0 'echo Testing Foundry MCP Server installation...$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'echo Checking Node.js...$\r$\n' FileWrite $0 '"$INSTDIR\node.exe" --version$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'echo Checking MCP Server files...$\r$\n' FileWrite $0 'if exist "$INSTDIR\foundry-mcp-server\packages\mcp-server\dist\index.cjs" ($\r$\n' FileWrite $0 ' echo ✓ MCP Server files found$\r$\n' FileWrite $0 ') else ($\r$\n' FileWrite $0 ' echo ✗ MCP Server files missing$\r$\n' FileWrite $0 ')$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'echo Installation test complete!$\r$\n' FileWrite $0 'pause$\r$\n' FileClose $0 ; Update Claude Desktop configuration DetailPrint "Configuring Claude Desktop..." Call UpdateClaudeConfig ; Success message DetailPrint "Foundry MCP Server installation complete!" SectionEnd ; Python Runtime is now included within ComfyUI section ;-------------------------------- ; Foundry Module Installation Section Section "Foundry MCP Bridge" SecFoundryModule ; This section is checked by default ; Set estimated size: Compiled JS + assets + templates (~5MB) SectionSetSize ${SecFoundryModule} 5120 ; Detect Foundry installation DetailPrint "Detecting Foundry VTT installation..." Call DetectFoundryInstallation ; Check if we found a valid Foundry path StrCmp $FoundryPath "" module_skipped module_install module_install: DetailPrint "Installing Foundry MCP Bridge Module to: $FoundryPath\foundry-mcp-bridge" ; Check if module already exists IfFileExists "$FoundryPath\foundry-mcp-bridge\module.json" existing_module new_install existing_module: DetailPrint "Existing module installation found - updating files..." Goto do_install new_install: DetailPrint "Installing fresh Foundry MCP Bridge module..." do_install: ; Create module directory CreateDirectory "$FoundryPath\foundry-mcp-bridge" SetOutPath "$FoundryPath\foundry-mcp-bridge" SetOverwrite on ; Copy all module files File /r "foundry-module\*" DetailPrint "Foundry MCP Bridge Module installed successfully" Goto module_done module_skipped: DetailPrint "Foundry module installation was skipped" module_done: SectionEnd ;-------------------------------- ; ComfyUI Map Generation Section Section "ComfyUI Map Generation" SecComfyUI ; Optional section for AI-powered map generation ; Will download additional 15.7GB for ComfyUI + AI models SectionSetSize ${SecComfyUI} 16515072 DetailPrint "Installing ComfyUI for AI-powered map generation..." ; Note: ComfyUI portable build includes its own Python runtime, so no separate Python installation needed DetailPrint "Preparing to download ComfyUI portable build with embedded Python..." ; ComfyUI directory will be created by 7z extraction ; Download ComfyUI portable Windows build DetailPrint "Downloading ComfyUI portable Windows build... (running silently)" ; Resolve download URL dynamically Call ResolveComfyUIDownload StrCmp $ComfyUIDownloadURL "" comfy_use_fallback comfy_use_resolved comfy_use_resolved: DetailPrint "Downloading ComfyUI portable Windows build..." Goto comfy_portable_download comfy_use_fallback: DetailPrint "Downloading ComfyUI portable Windows build..." Goto comfy_portable_download comfy_portable_download: DetailPrint "This may take several minutes depending on your internet connection..." ; Clean up any existing ComfyUI installation DetailPrint "Cleaning up any existing ComfyUI installation..." RMDir /r "$INSTDIR\ComfyUI" ; Download ComfyUI portable Windows build (no git required) DetailPrint "Downloading ComfyUI Windows portable build from GitHub (~2GB)..." DetailPrint "This will take several minutes depending on your internet speed..." ; Create download directory in installation folder to avoid temp space issues DetailPrint "Creating download directory..." CreateDirectory "$INSTDIR\temp" ; Download with extended timeout (20 minutes) for large file ; Check if URL resolution succeeded StrCmp $ComfyUIDownloadURL "" url_resolution_failed download_comfyui url_resolution_failed: DetailPrint "Failed to resolve ComfyUI download URL" MessageBox MB_ICONEXCLAMATION|MB_YESNO "Failed to resolve ComfyUI download URL from GitHub API.$\r$\n$\r$\nThis may be due to:$\r$\n• Network connectivity issues$\r$\n• GitHub API rate limiting$\r$\n• Firewall blocking API access$\r$\n$\r$\nWould you like to continue without ComfyUI?$\r$\n(You can install it manually later)" IDYES skip_comfyui IDNO comfy_portable_download download_comfyui: DetailPrint "Using resolved download URL: $ComfyUIDownloadName" inetc::get /SILENT /RECEIVETIMEOUT 1200 "$ComfyUIDownloadURL" "$INSTDIR\temp\ComfyUI_windows_portable.7z" Pop $0 StrCmp $0 "OK" download_success download_failed download_failed: DetailPrint "ComfyUI download failed: $0" ; Check if it's a file access issue specifically StrCmp $0 "File Open Error" file_access_error generic_download_error file_access_error: MessageBox MB_ICONEXCLAMATION|MB_RETRYCANCEL "File Access Error$\r$\n$\r$\nUnable to create or write to download file.$\r$\n$\r$\nTry running installer as Administrator." IDRETRY comfy_portable_download IDCANCEL skip_comfyui generic_download_error: MessageBox MB_ICONEXCLAMATION|MB_YESNO "Download Failed: $0$\r$\n$\r$\nWould you like to try an alternative download method?$\r$\n$\r$\nYES - Try PowerShell download$\r$\nNO - Skip ComfyUI installation" IDYES try_alternative_download IDNO skip_comfyui try_alternative_download: DetailPrint "Attempting alternative download using PowerShell..." ; Create PowerShell download script FileOpen $6 "$INSTDIR\temp\download-comfyui.ps1" w FileWrite $6 'param([string]$$outputPath)$\r$\n' FileWrite $6 '$$ProgressPreference = "SilentlyContinue"$\r$\n' FileWrite $6 'try {$\r$\n' ; Use resolved URL (required) FileWrite $6 ' $$uri = "$ComfyUIDownloadURL"$\r$\n' FileWrite $6 ' Write-Host "Starting PowerShell download of ComfyUI..."$\r$\n' FileWrite $6 ' Invoke-WebRequest -Uri $$uri -OutFile $$outputPath -TimeoutSec 1200$\r$\n' FileWrite $6 ' if (Test-Path $$outputPath) {$\r$\n' FileWrite $6 ' $$size = [math]::Round((Get-Item $$outputPath).Length / 1MB, 2)$\r$\n' FileWrite $6 ' Write-Host "Download completed successfully. Size: $$size MB"$\r$\n' FileWrite $6 ' exit 0$\r$\n' FileWrite $6 ' } else {$\r$\n' FileWrite $6 ' throw "File not created"$\r$\n' FileWrite $6 ' }$\r$\n' FileWrite $6 '} catch {$\r$\n' FileWrite $6 ' Write-Host "PowerShell download failed: $$($_.Exception.Message)"$\r$\n' FileWrite $6 ' exit 1$\r$\n' FileWrite $6 '}$\r$\n' FileClose $6 ; Execute PowerShell download DetailPrint "Executing PowerShell download (this may take 10-20 minutes)..." ${PowerShellExecFile} "$INSTDIR\temp\download-comfyui.ps1" '"$INSTDIR\temp\ComfyUI_windows_portable.7z"' Pop $7 ; Exit code Pop $8 ; Output ; Clean up PowerShell script Delete "$INSTDIR\temp\download-comfyui.ps1" DetailPrint "PowerShell download exit code: $7" DetailPrint "PowerShell output: $8" IntCmp $7 0 powershell_download_success powershell_download_failed powershell_download_failed powershell_download_failed: DetailPrint "PowerShell download also failed" MessageBox MB_ICONEXCLAMATION|MB_YESNO "Both download methods failed.$\r$\n$\r$\nWould you like to continue without ComfyUI?$\r$\n(You can install it manually later)" IDYES skip_comfyui IDNO comfy_portable_download powershell_download_success: DetailPrint "PowerShell download succeeded!" Goto download_success download_success: DetailPrint "ComfyUI downloaded successfully" ; Extract the portable build to ComfyUI directory ; Using embedded 7zr.exe because ComfyUI archives require full 7z support DetailPrint "Extracting ComfyUI portable build (this may take a few minutes)..." InitPluginsDir File /oname=$PLUGINSDIR\7zr.exe "7zr.exe" DetailPrint "Running 7-Zip extraction..." nsExec::ExecToStack '"$PLUGINSDIR\7zr.exe" x "-y" "-bsp0" "-bso0" "-o$INSTDIR" "$INSTDIR\temp\ComfyUI_windows_portable.7z"' Pop $0 ; Exit code Pop $9 ; stdout/stderr output IntCmp $0 0 extract_success extract_failed extract_failed extract_failed: DetailPrint "ComfyUI extraction failed (exit code $0)" DetailPrint "7-Zip command: x -y -bsp0 -bso0 -o$INSTDIR" DetailPrint "Archive path: $INSTDIR\temp\ComfyUI_windows_portable.7z" ${If} $9 != "" DetailPrint "7-Zip output: $9" ${Else} DetailPrint "No 7-Zip output captured" ${EndIf} ; Cleanup temp files on failure Delete "$INSTDIR\temp\ComfyUI_windows_portable.7z" RMDir "$INSTDIR\temp" MessageBox MB_ICONEXCLAMATION|MB_RETRYCANCEL "ComfyUI extraction failed (exit code $0).$\r$\n$\r$\n7-Zip error details:$\r$\n$9$\r$\n$\r$\nWould you like to retry the download and extraction?" IDRETRY comfy_portable_download IDCANCEL skip_comfyui extract_success: DetailPrint "ComfyUI extracted successfully" ; Clean up downloaded archive Delete "$INSTDIR\temp\ComfyUI_windows_portable.7z" RMDir "$INSTDIR\temp" ; The portable build extracts to ComfyUI_windows_portable, so we need to rename it Rename "$INSTDIR\ComfyUI_windows_portable" "$INSTDIR\ComfyUI" ; Download essential models for battlemap generation DetailPrint "Downloading essential models for map generation..." Call DownloadComfyUIModels Goto comfyui_scripts skip_comfyui: DetailPrint "ComfyUI installation skipped" Goto comfyui_scripts comfyui_scripts: ; Create ComfyUI batch scripts DetailPrint "Creating ComfyUI utility scripts..." ; Start ComfyUI script using portable build's embedded Python FileOpen $0 "$INSTDIR\start-comfyui.bat" w FileWrite $0 '@echo off$\r$\n' FileWrite $0 'echo Starting ComfyUI for map generation...$\r$\n' FileWrite $0 'REM Set defaults if environment variables not set$\r$\n' FileWrite $0 'if not defined COMFYUI_HOST set COMFYUI_HOST=127.0.0.1$\r$\n' FileWrite $0 'if not defined COMFYUI_PORT set COMFYUI_PORT=31411$\r$\n' FileWrite $0 'echo Using ComfyUI Host: %COMFYUI_HOST%$\r$\n' FileWrite $0 'echo Using ComfyUI Port: %COMFYUI_PORT%$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'REM Check for ComfyUI portable installation$\r$\n' FileWrite $0 'if exist "$INSTDIR\ComfyUI\main.py" ($\r$\n' FileWrite $0 ' echo Using ComfyUI portable installation with embedded Python$\r$\n' FileWrite $0 ' cd /d "$INSTDIR\ComfyUI"$\r$\n' FileWrite $0 ' echo Starting ComfyUI with GPU optimization... > "$INSTDIR\comfyui.log"$\r$\n' FileWrite $0 ' "python_embeded\python.exe" main.py --port %COMFYUI_PORT% --listen %COMFYUI_HOST% --disable-auto-launch --dont-print-server >> "$INSTDIR\comfyui.log" 2>&1$\r$\n' FileWrite $0 ') else ($\r$\n' FileWrite $0 ' echo ERROR: ComfyUI portable installation not found$\r$\n' FileWrite $0 ' echo Expected: $INSTDIR\ComfyUI\main.py$\r$\n' FileWrite $0 ' echo Please reinstall ComfyUI Map Generation component$\r$\n' FileWrite $0 ' pause$\r$\n' FileWrite $0 ' exit /b 1$\r$\n' FileWrite $0 ')$\r$\n' FileWrite $0 'pause$\r$\n' FileClose $0 ; Test ComfyUI script with comprehensive checks FileOpen $0 "$INSTDIR\test-comfyui.bat" w FileWrite $0 '@echo off$\r$\n' FileWrite $0 'echo Testing ComfyUI portable installation...$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'echo === Checking ComfyUI Portable Installation ===$\r$\n' FileWrite $0 'if exist "$INSTDIR\ComfyUI\main.py" ($\r$\n' FileWrite $0 ' echo ✓ ComfyUI portable installation found$\r$\n' FileWrite $0 ' echo Location: $INSTDIR\ComfyUI\main.py$\r$\n' FileWrite $0 ') else ($\r$\n' FileWrite $0 ' echo ✗ ComfyUI portable installation not found$\r$\n' FileWrite $0 ' echo Expected: $INSTDIR\ComfyUI\main.py$\r$\n' FileWrite $0 ')$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'echo === Checking Embedded Python ===$\r$\n' FileWrite $0 'if exist "$INSTDIR\ComfyUI\python_embeded\python.exe" ($\r$\n' FileWrite $0 ' echo ✓ Embedded Python runtime found$\r$\n' FileWrite $0 ' echo Location: $INSTDIR\ComfyUI\python_embeded\python.exe$\r$\n' FileWrite $0 ' echo Version: $\r$\n' FileWrite $0 ' "$INSTDIR\ComfyUI\python_embeded\python.exe" --version$\r$\n' FileWrite $0 ') else ($\r$\n' FileWrite $0 ' echo ✗ Embedded Python runtime not found$\r$\n' FileWrite $0 ' echo Expected: $INSTDIR\ComfyUI\python_embeded\python.exe$\r$\n' FileWrite $0 ')$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'echo === Checking PyTorch Installation ===$\r$\n' FileWrite $0 'if exist "$INSTDIR\ComfyUI\python_embeded\python.exe" ($\r$\n' FileWrite $0 ' echo Testing PyTorch CUDA availability...$\r$\n' FileWrite $0 ' cd /d "$INSTDIR\ComfyUI"$\r$\n' FileWrite $0 ' "python_embeded\python.exe" -c "import torch; print(f\\\"PyTorch: {torch.__version__}\\\"); print(f\\\"CUDA available: {torch.cuda.is_available()}\\\"); print(f\\\"CUDA devices: {torch.cuda.device_count()}\\\")"$\r$\n' FileWrite $0 ') else ($\r$\n' FileWrite $0 ' echo Cannot test PyTorch - embedded Python not found$\r$\n' FileWrite $0 ')$\r$\n' FileWrite $0 'echo.$\r$\n' FileWrite $0 'echo === Test Complete ===$\r$\n' FileWrite $0 'echo If all components show ✓, ComfyUI should work correctly.$\r$\n' FileWrite $0 'echo Logs are saved to: $INSTDIR\comfyui.log$\r$\n' FileWrite $0 'pause$\r$\n' FileClose $0 ; Add ComfyUI test shortcut to Start Menu (for troubleshooting only) CreateShortcut "$SMPROGRAMS\Foundry MCP Server\Test ComfyUI.lnk" "$INSTDIR\test-comfyui.bat" "" "$INSTDIR\icon.ico" DetailPrint "ComfyUI installation complete!" SectionEnd ;-------------------------------- ; Section Descriptions !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecMain} "The core Foundry MCP Server that connects Claude Desktop to Foundry VTT. Includes Node.js runtime and MCP server. Required component (~32MB)." !insertmacro MUI_DESCRIPTION_TEXT ${SecFoundryModule} "Install the Foundry MCP Bridge module directly to your Foundry VTT for seamless AI-powered campaign management. Includes compiled JavaScript, templates, and assets (~5MB)." !insertmacro MUI_DESCRIPTION_TEXT ${SecComfyUI} "Optional AI battlemap generation (~15.7GB total). Includes ComfyUI, Python runtime, SDXL models, and PyTorch." !insertmacro MUI_FUNCTION_DESCRIPTION_END ;-------------------------------- ; Uninstaller Section Section "Uninstall" DetailPrint "Starting Foundry MCP Server uninstallation..." ; Remove MCP Server files and directories DetailPrint "Removing MCP Server files..." Delete "$INSTDIR\node.exe" RMDir /r "$INSTDIR\node" RMDir /r "$INSTDIR\node_modules" RMDir /r "$INSTDIR\foundry-mcp-server" Delete "$INSTDIR\README.txt" Delete "$INSTDIR\LICENSE.txt" Delete "$INSTDIR\configure-claude.ps1" Delete "$INSTDIR\configure-claude-wrapper.bat" Delete "$INSTDIR\start-server.bat" Delete "$INSTDIR\test-connection.bat" Delete "$INSTDIR\start-comfyui.bat" Delete "$INSTDIR\test-comfyui.bat" Delete "$INSTDIR\THIRD_PARTY_NOTICES.txt" Delete "$INSTDIR\icon.ico" ; Remove ComfyUI portable installation DetailPrint "Removing ComfyUI portable installation..." RMDir /r "$INSTDIR\ComfyUI" RMDir /r "$INSTDIR\ComfyUI" ; Remove any remaining files in installation directory Delete "$INSTDIR\*.*" ; Remove Start Menu shortcuts DetailPrint "Removing Start Menu shortcuts..." RMDir /r "$SMPROGRAMS\Foundry MCP Server" ; Remove registry entries DetailPrint "Removing registry entries..." DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\FoundryMCPServer" ; Ask about Foundry module removal MessageBox MB_YESNO "Do you want to remove the Foundry MCP Bridge module from your Foundry VTT installation?$\r$\n$\r$\n(This will not affect your worlds, actors, or other Foundry data)" IDYES remove_foundry_module IDNO skip_foundry_removal remove_foundry_module: DetailPrint "Checking for Foundry module installation..." Call un.DetectFoundryModule StrCmp $un.FoundryPath "" foundry_not_found remove_foundry_files remove_foundry_files: DetailPrint "Removing Foundry MCP Bridge module from: $un.FoundryPath" RMDir /r "$un.FoundryPath\foundry-mcp-bridge" IfFileExists "$un.FoundryPath\foundry-mcp-bridge" foundry_removal_failed foundry_removal_success foundry_removal_failed: DetailPrint "Warning: Could not completely remove Foundry module files" Goto skip_foundry_removal foundry_removal_success: DetailPrint "Foundry MCP Bridge module removed successfully" Goto skip_foundry_removal foundry_not_found: DetailPrint "Foundry module installation not detected" skip_foundry_removal: ; Ask about Claude Desktop configuration removal MessageBox MB_YESNO "Do you want to remove the Foundry MCP Server entry from your Claude Desktop configuration?$\r$\n$\r$\n(Recommended - this will not affect other MCP servers)" IDYES remove_claude_config IDNO skip_claude_config remove_claude_config: DetailPrint "Removing Claude Desktop configuration entry..." Call un.RemoveClaudeConfig Goto skip_claude_config skip_claude_config: ; Remove installation directory RMDir "$INSTDIR" Delete "$INSTDIR\Uninstall.exe" DetailPrint "Uninstallation completed successfully" MessageBox MB_ICONINFORMATION "Foundry MCP Server has been successfully uninstalled.$\r$\n$\r$\nIf you removed the Claude Desktop configuration, please restart Claude Desktop." SectionEnd Function un.DetectFoundryModule ; Try to detect Foundry module installation for removal StrCpy $un.FoundryPath "" ; Check primary location StrCpy $un.FoundryPath "$LOCALAPPDATA\FoundryVTT\Data\modules" IfFileExists "$un.FoundryPath\foundry-mcp-bridge\module.json" foundry_module_found ; Check secondary location StrCpy $un.FoundryPath "$APPDATA\FoundryVTT\Data\modules" IfFileExists "$un.FoundryPath\foundry-mcp-bridge\module.json" foundry_module_found ; Check environment variable ReadEnvStr $0 "FOUNDRY_VTT_DATA_PATH" StrCmp $0 "" manual_search StrCpy $un.FoundryPath "$0\Data\modules" IfFileExists "$un.FoundryPath\foundry-mcp-bridge\module.json" foundry_module_found manual_search: ; Ask user to locate Foundry installation MessageBox MB_YESNO "Foundry MCP Bridge module not found automatically.$\r$\n$\r$\nWould you like to browse for your Foundry User Data folder to remove the module?" IDYES browse_for_foundry IDNO module_not_found browse_for_foundry: nsDialogs::SelectFolderDialog "Select Foundry VTT User Data Folder" "$LOCALAPPDATA" Pop $0 StrCmp $0 CANCEL module_not_found StrCpy $un.FoundryPath "$0\Data\modules" IfFileExists "$un.FoundryPath\foundry-mcp-bridge\module.json" foundry_module_found module_not_found: StrCpy $un.FoundryPath "" Return foundry_module_found: DetailPrint "Found Foundry module at: $un.FoundryPath\foundry-mcp-bridge" FunctionEnd Function un.GetClaudeConfigPath ; Find Claude Desktop configuration file StrCpy $un.ClaudeConfigPath "$APPDATA\Claude\claude_desktop_config.json" IfFileExists $un.ClaudeConfigPath config_found StrCpy $un.ClaudeConfigPath "$LOCALAPPDATA\Claude\claude_desktop_config.json" IfFileExists $un.ClaudeConfigPath config_found StrCpy $un.ClaudeConfigPath "" config_found: FunctionEnd Function un.RemoveClaudeConfig ; Remove Foundry MCP Server entry from Claude Desktop config Call un.GetClaudeConfigPath StrCmp $un.ClaudeConfigPath "" no_config_found ; Create backup before modification StrCpy $2 "$un.ClaudeConfigPath.backup" CopyFiles $un.ClaudeConfigPath "$2" DetailPrint "Created backup at: $2" ; Create temporary PowerShell script for config removal FileOpen $4 "$TEMP\remove-foundry-mcp.ps1" w FileWrite $4 "try {$\r$\n" FileWrite $4 " Write-Host 'Removing foundry-mcp from Claude Desktop config'$\r$\n" FileWrite $4 " $$configPath = '$un.ClaudeConfigPath'$\r$\n" FileWrite $4 " Write-Host 'Config path:' $$configPath$\r$\n" FileWrite $4 " $$config = Get-Content $$configPath -Raw | ConvertFrom-Json$\r$\n" FileWrite $4 " if ($$config.mcpServers -and $$config.mcpServers.'foundry-mcp') {$\r$\n" FileWrite $4 " $$config.mcpServers.PSObject.Properties.Remove('foundry-mcp')$\r$\n" FileWrite $4 " $$json = $$config | ConvertTo-Json -Depth 10$\r$\n" FileWrite $4 " [System.IO.File]::WriteAllText($$configPath, $$json, [System.Text.UTF8Encoding]::new($$false))$\r$\n" FileWrite $4 " Write-Host 'SUCCESS: foundry-mcp entry removed from Claude config'$\r$\n" FileWrite $4 " } else {$\r$\n" FileWrite $4 " Write-Host 'INFO: foundry-mcp entry not found in config'$\r$\n" FileWrite $4 " }$\r$\n" FileWrite $4 "} catch {$\r$\n" FileWrite $4 " Write-Host 'ERROR:' $$_.Exception.Message$\r$\n" FileWrite $4 " exit 1$\r$\n" FileWrite $4 "}$\r$\n" FileClose $4 ; Execute the temporary PowerShell script ${PowerShellExecWithOutput} 'powershell.exe -inputformat none -NoProfile -ExecutionPolicy Bypass -File "$TEMP\remove-foundry-mcp.ps1"' ; Clean up temp script Delete "$TEMP\remove-foundry-mcp.ps1" Pop $0 ; Exit code Pop $1 ; Output IntCmp $0 0 config_success config_failed config_failed config_success: DetailPrint "Claude Desktop configuration updated successfully" DetailPrint "PowerShell output: $1" Return config_failed: DetailPrint "Failed to update Claude Desktop configuration (exit code: $0)" DetailPrint "PowerShell output: $1" MessageBox MB_ICONEXCLAMATION "Failed to remove Foundry MCP Server from Claude Desktop configuration.$\r$\n$\r$\nYou may need to manually remove the 'foundry-mcp' entry from:$\r$\n$un.ClaudeConfigPath$\r$\n$\r$\nA backup was created at:$\r$\n$un.ClaudeConfigPath.backup" Return no_config_found: DetailPrint "Claude Desktop configuration file not found" MessageBox MB_ICONINFORMATION "Claude Desktop configuration file not found - no configuration changes needed." FunctionEnd

Latest Blog Posts

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/adambdooley/foundry-vtt-mcp'

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