Skip to content

feat(mcp): add Windows PowerShell installer#444

Open
mynameistito wants to merge 4 commits intodmtrKovalenko:mainfrom
mynameistito:windows-mcp-installer
Open

feat(mcp): add Windows PowerShell installer#444
mynameistito wants to merge 4 commits intodmtrKovalenko:mainfrom
mynameistito:windows-mcp-installer

Conversation

@mynameistito
Copy link
Copy Markdown

@mynameistito mynameistito commented May 4, 2026

Summary

Closes #364.

Adds install-mcp.ps1, a PowerShell mirror of install-mcp.sh, so Windows users can install the fff-mcp binary with a one-liner. README updated with the Windows command alongside the existing Unix one.

The release workflow already publishes fff-mcp-x86_64-pc-windows-msvc.exe and fff-mcp-aarch64-pc-windows-msvc.exe, so no CI changes needed — the script just consumes existing assets.

What it does

  • Detects AMD64 / ARM64 (honoring PROCESSOR_ARCHITEW6432 for WOW64).
  • Picks the latest release containing the matching asset (mirrors the bash awk logic via Invoke-RestMethod).
  • Downloads + verifies SHA256 (skips with a warning if .sha256 is missing, same as bash).
  • Installs to $env:LOCALAPPDATA\fff-mcp\bin (overridable via FFF_MCP_INSTALL_DIR).
  • Adds install dir to user PATH if not already present.
  • Detects claude / opencode / codex and prints the same wiring snippets as the bash script.
  • Update path: re-runs in-place if binary already exists, prints succinct "updated to <tag>" message.

Invocation

irm https://raw.githubusercontent.com/dmtrKovalenko/fff.nvim/main/install-mcp.ps1 | iex

(Eventually you may want to host this on dmtrkovalenko.dev/install-fff-mcp.ps1 for symmetry — README points at the raw GitHub URL for now.)

Checklist

  • No changes to Rust / Lua / public APIs
  • No CI workflow changes (existing Windows release assets reused)
  • PowerShell 5.1+ compatible (ships with Windows 10/11 — no extra deps)
  • Honors FFF_MCP_INSTALL_DIR env override (parity with bash)
  • SHA256 verification when checksum file present
  • Idempotent: re-running upgrades in place
  • Adds install dir to user PATH only if missing
  • README updated with both Linux/macOS and Windows install snippets
  • Script syntax validated via [System.Management.Automation.PSParser]::Tokenize
  • End-to-end install tested on a fresh Windows machine (deferred — needs a real release with Windows assets to download)
  • ARM64 Windows tested (no hardware available)

Test plan

  • On Windows AMD64: run the one-liner, confirm fff-mcp.exe lands in %LOCALAPPDATA%\fff-mcp\bin, confirm it is on PATH in a new shell, confirm fff-mcp --help (or equivalent) runs.
  • Re-run installer, confirm "Updating..." path triggers and binary is replaced.
  • Set $env:FFF_MCP_INSTALL_DIR to a custom dir, confirm install lands there.
  • Delete the .sha256 upstream temporarily (or test against a release missing it) and confirm the script warns instead of failing.
  • Confirm Claude Code / OpenCode / Codex detection prints the right snippet when those CLIs are on PATH.

@mynameistito
Copy link
Copy Markdown
Author

All done with Claude Opus 4.7 and worked as intended for me :)

Did not read any of the code, just tested the outcome happy to make itterations should you wish @dmtrKovalenko

@dmtrKovalenko
Copy link
Copy Markdown
Owner

dmtrKovalenko commented May 4, 2026

I have no idea is this right or not and do not understand anything in powershell but my opus 4.7 told this LMAO

  - TLS 1.2 not forced. install-mcp.ps1:33 calls Invoke-RestMethod against api.github.com without setting      
  [Net.ServicePointManager]::SecurityProtocol. On PS 5.1 (the minimum version required) on older Win10 builds,
  SecurityProtocol can still default to SSL3/TLS1.0, and GitHub rejects those. Common pitfall in PowerShell    
  installers — recommend adding near the top:
  [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor
  [Net.SecurityProtocolType]::Tls12
  - Wrong exception type for missing SHA256. install-mcp.ps1:66 catches [System.Net.WebException], but on
  PowerShell 7+ a 404 from Invoke-WebRequest throws Microsoft.PowerShell.Commands.HttpResponseException, not
  WebException. Since #Requires -Version 5.1 admits PS 7, and $ErrorActionPreference = 'Stop', a missing
  checksum file will abort the install instead of warning — the exact opposite of the bash script's behavior.
  Use a generic catch or catch both types:
  } catch {
      if ($_.Exception -is [System.Net.WebException] -or $_.Exception.GetType().Name -eq
  'HttpResponseException') {
          Write-Warn "Checksum file not available, skipping verification."
      } else { throw }
  }

I think we should get rid of sha256 check at all

Addresses review feedback on PR dmtrKovalenko#444:
- Force TLS 1.2 on PS 5.1 / older Win10 where SecurityProtocol may default to SSL3/TLS1.0 and GitHub rejects.
- Drop sha256 verification entirely. Avoids PS 5.1 vs PS 7 exception-type mismatch (WebException vs HttpResponseException) where ErrorActionPreference=Stop would abort on a missing checksum file instead of warning.
@mynameistito
Copy link
Copy Markdown
Author

mynameistito commented May 4, 2026

that was what my opus thought, maybe good to get other eyes on it but it works as intended for me :)

@mynameistito
Copy link
Copy Markdown
Author

Both points valid — pushed db25a30:

  • Forced TLS 1.2 at top of script via [Net.ServicePointManager]::SecurityProtocol = ... -bor [Net.SecurityProtocolType]::Tls12.
  • Dropped sha256 verification entirely per your call. Kills the WebException vs HttpResponseException mismatch and halves the script's failure surface. Bash version's check was best-effort anyway.

Copy link
Copy Markdown

@ccastanedaucf ccastanedaucf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Comment thread install-mcp.ps1
Comment thread install-mcp.ps1 Outdated
Comment thread install-mcp.ps1
Comment thread install-mcp.ps1 Outdated
Comment thread install-mcp.ps1 Outdated
- Add -Version and -InstallDir params (with FFF_MCP_VERSION / FFF_MCP_INSTALL_DIR env-var fallbacks for irm | iex usage).
- Detect arch via registry (HKLM\...\Environment) instead of $env:PROCESSOR_ARCHITECTURE — env vars lie under x86/ARM64 emulation.
- Skip release-list scan when -Version is pinned.
- Prefer curl.exe (ships with Win10 1803+) for downloads, fall back to iwr with $ProgressPreference='SilentlyContinue' to dodge PS 5.1's slow progress bar.
- Append install dir to current-session PATH so the user does not need a new shell.
@mynameistito
Copy link
Copy Markdown
Author

Thanks @ccastanedaucf — pushed 47d6006 with all five:

  • Params: added -Version and -InstallDir. Pipe form keeps working via FFF_MCP_VERSION / FFF_MCP_INSTALL_DIR env-var fallbacks, since irm | iex can't bind params.
  • Arch detect: switched to HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment, dropped the env-var dance.
  • Release scan: kept the asset-aware scan as the default path (the bash script does the same — not every release publishes the MCP exe), but -Version short-circuits it.
  • Download: curl.exe primary with iwr fallback; iwr path wraps $ProgressPreference = 'SilentlyContinue' in try/finally to keep PS 5.1 throughput sane.
  • PATH: also appends to $env:PATH for the current session so no shell restart is needed.

Comment thread install-mcp.ps1
Comment on lines +117 to +129
function Add-ToUserPath {
param([string]$Dir)
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if (-not $userPath) { $userPath = '' }
$entries = $userPath -split ';' | Where-Object { $_ -ne '' }
if ($entries -notcontains $Dir) {
$newPath = (@($entries + $Dir) -join ';')
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
Write-Success "Added $Dir to user PATH."
}
# Make available in current session too — no shell restart needed.
if (-not (Test-OnPath $Dir)) { $env:PATH = "$env:PATH;$Dir" }
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth, some pwsh users such as myself prefer appending to $profile *nix-style rather than modifying the environment variable globally; there could probably be a script param to control this behavior.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the feedback pushing another commit out now.

Per @PurpleMyst feedback: some pwsh users prefer appending to $PROFILE *nix-style
rather than setting the user environment variable globally.

-PathScope User    (default) — set HKCU Environment.Path (existing behavior)
-PathScope Profile — append `$env:PATH += ';...'` to $PROFILE.CurrentUserAllHosts
-PathScope None    — skip persistence entirely

Env-var fallback: FFF_MCP_PATH_SCOPE (for the irm | iex case).
Current-session $env:PATH still updated regardless of scope.
@mynameistito
Copy link
Copy Markdown
Author

Thanks @PurpleMyst — pushed 61fc7e8 with a -PathScope param:

  • -PathScope User (default) — sets the user env var, current behavior.
  • -PathScope Profile — appends $env:PATH += ';...' to $PROFILE.CurrentUserAllHosts, *nix-style.
  • -PathScope None — skip persistence entirely.

Env-var fallback FFF_MCP_PATH_SCOPE for the irm | iex case. Current-session $env:PATH is still updated regardless of scope so the binary is usable immediately.

@PurpleMyst
Copy link
Copy Markdown
Contributor

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows Support

4 participants