-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.ps1
More file actions
147 lines (131 loc) · 6.1 KB
/
Copy pathinstall.ps1
File metadata and controls
147 lines (131 loc) · 6.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# UTMStack MCP server installer (Windows)
#
# irm https://raw.githubusercontent.com/utmstack/MCP/main/install.ps1 | iex
#
# Downloads the release build for this platform, verifies its SHA256 against
# the checksums published with the release, and installs it.
$ErrorActionPreference = 'Stop'
# On PowerShell 5.1 the Invoke-WebRequest progress bar makes large
# downloads roughly an order of magnitude slower.
$ProgressPreference = 'SilentlyContinue'
$Repo = 'utmstack/MCP'
$App = 'utmstack-mcp'
$Version = if ($env:UTMSTACK_MCP_VERSION) { $env:UTMSTACK_MCP_VERSION } else { 'latest' }
function Info($m) { Write-Host $m }
# `throw`, not `exit`: `irm ... | iex` runs in the caller's scope, so `exit`
# closes the user's console, and inside a &-invoked scriptblock (how the
# CLI installer calls this one) it escapes the caller's try/catch.
function Fail($m) { throw "utmstack-mcp install: $m" }
# --- platform ------------------------------------------------------------- #
# Under WOW64 a 32-bit PowerShell host reports x86 on an x64 machine.
$rawArch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
$arch = switch ($rawArch) {
'AMD64' { 'amd64' }
'ARM64' { 'arm64' }
default { Fail "unsupported architecture: $rawArch" }
}
$asset = "$App-windows-$arch.zip"
# --- resolve release ------------------------------------------------------ #
$api = if ($Version -eq 'latest') {
"https://api.github.com/repos/$Repo/releases/latest"
} else {
# Releases are tagged "v1.2.3". Accept the version with or without the v,
# since the README documents the bare form.
"https://api.github.com/repos/$Repo/releases/tags/v$($Version -replace '^v','')"
}
Info "Resolving $Version release of $Repo ..."
try {
$release = Invoke-RestMethod -Uri $api -UseBasicParsing
} catch {
Fail "could not resolve a release (is the repository public and does it have a release?)"
}
$tag = $release.tag_name
if (-not $tag) { Fail 'no tag_name in release response' }
Info " version: $tag"
$base = "https://github.com/$Repo/releases/download/$tag"
$tmp = Join-Path $env:TEMP ("utmstack-mcp-install-" + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Force -Path $tmp | Out-Null
try {
# --- download + verify ------------------------------------------------ #
Info "Downloading $asset ..."
$pkg = Join-Path $tmp $asset
try {
Invoke-WebRequest -Uri "$base/$asset" -OutFile $pkg -UseBasicParsing
} catch {
Fail "no build published for windows/$arch in $tag"
}
Info 'Verifying checksum ...'
$sumFile = Join-Path $tmp 'checksums.txt'
try {
Invoke-WebRequest -Uri "$base/checksums.txt" -OutFile $sumFile -UseBasicParsing
} catch {
Fail 'could not download checksums.txt - refusing to install unverified binary'
}
$expected = $null
foreach ($line in Get-Content $sumFile) {
if ($line -match "^([0-9a-fA-F]{64})\s+\*?$([regex]::Escape($asset))$") {
$expected = $Matches[1].ToLower(); break
}
}
if (-not $expected) { Fail "no checksum listed for $asset - refusing to install" }
$actual = (Get-FileHash -Path $pkg -Algorithm SHA256).Hash.ToLower()
if ($expected -ne $actual) { Fail "checksum mismatch - expected $expected, got $actual" }
Info ' checksum OK'
# --- install ---------------------------------------------------------- #
$libDir = Join-Path $env:LOCALAPPDATA "Programs\$App"
if (Test-Path $libDir) {
# Windows will not delete a running executable. On upgrade the previous
# utmstack-mcp is often still spawned by an MCP client, and an
# unguarded Remove-Item throws after partially deleting the directory.
try {
Remove-Item -Recurse -Force $libDir -ErrorAction Stop
} catch {
Fail "could not replace $libDir - utmstack-mcp may be running. Close your MCP client (Claude Code, OpenCode, ...) and re-run."
}
}
New-Item -ItemType Directory -Force -Path $libDir | Out-Null
Info "Installing to $libDir ..."
# Prefer tar (bsdtar, shipped on Windows 10+): Expand-Archive is very slow on
# ARM for a many-file zip, and this one carries 160 files. Fall back to
# Expand-Archive where tar is unavailable.
$tar = Get-Command tar.exe -ErrorAction SilentlyContinue
if ($tar) {
& $tar.Source -xf $pkg -C $tmp
if ($LASTEXITCODE -ne 0) { Expand-Archive -Path $pkg -DestinationPath $tmp -Force }
} else {
Expand-Archive -Path $pkg -DestinationPath $tmp -Force
}
$src = Get-ChildItem -Path $tmp -Directory | Where-Object { $_.Name -like "$App*" } | Select-Object -First 1
if (-not $src) { Fail 'unexpected archive layout' }
Copy-Item -Path (Join-Path $src.FullName '*') -Destination $libDir -Recurse -Force
$exe = Join-Path $libDir "$App.exe"
if (-not (Test-Path $exe)) { Fail "installed archive has no $App.exe" }
# --- PATH ------------------------------------------------------------- #
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if ($userPath -notlike "*$libDir*") {
Info "Adding $libDir to your user PATH ..."
$newPath = if ($userPath) { "$userPath;$libDir" } else { $libDir }
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
$env:Path = "$env:Path;$libDir"
$pathNote = $true
}
$installed = (& $exe --version 2>&1 | Out-String).Trim()
Info ''
Info "Installed $installed"
Info " binary: $exe"
if ($pathNote) {
Info ''
Info ' NOTE: PATH was updated. Open a new terminal for `utmstack-mcp` to resolve.'
}
Info ''
Info 'Next steps:'
Info " 1. $App init # configure your UTMStack connection"
Info ' 2. Register with a client:'
Info " Claude Code: claude mcp add --scope user utmstack -- $App"
Info ' OpenCode: add to %USERPROFILE%\.config\opencode\opencode.json:'
Info " {`"mcp`":{`"utmstack`":{`"type`":`"local`",`"command`":[`"$App`"],`"enabled`":true}}}"
Info ''
}
finally {
Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue
}