Skip to content

Commit d250653

Browse files
committed
install files
1 parent 06ca413 commit d250653

2 files changed

Lines changed: 323 additions & 0 deletions

File tree

install.ps1

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<#
2+
.SYNOPSIS
3+
One-shot installer for the TestOps MCP server (per-user / stdio mode).
4+
5+
.DESCRIPTION
6+
Downloads the right binary for your OS/arch from GitHub Releases, asks for your
7+
Allure TestOps URL + API token, and registers the server in BOTH:
8+
* Claude Desktop (claude_desktop_config.json)
9+
* Claude Code (via `claude mcp add -s user`, if the CLI is installed)
10+
11+
Re-running the script is safe — it overwrites the existing "testops" entry.
12+
13+
.EXAMPLE
14+
# Interactive (asks for URL + token):
15+
powershell -ExecutionPolicy Bypass -File .\install.ps1
16+
17+
.EXAMPLE
18+
# Non-interactive:
19+
powershell -ExecutionPolicy Bypass -File .\install.ps1 `
20+
-AllureBaseUrl https://your-testops.com -AllureToken xxxxxxxx
21+
#>
22+
[CmdletBinding()]
23+
param(
24+
[string]$AllureBaseUrl = $env:ALLURE_BASE_URL,
25+
[string]$AllureToken = $env:ALLURE_TOKEN,
26+
[string]$Version = "latest", # e.g. v2.0.3 ; "latest" = newest release
27+
[string]$ServerName = "testops",
28+
[switch]$NoClaudeCode,
29+
[switch]$NoClaudeDesktop
30+
)
31+
32+
$ErrorActionPreference = "Stop"
33+
$Repo = "MimoJanra/TestOpsMCP"
34+
35+
# TestOps MCP supports older Windows that default to TLS 1.0/1.1.
36+
try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {}
37+
38+
function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
39+
function Write-Ok($msg) { Write-Host " OK $msg" -ForegroundColor Green }
40+
function Write-Warn2($msg) { Write-Host " ! $msg" -ForegroundColor Yellow }
41+
42+
function Update-DesktopConfig {
43+
param([string]$Path, [string]$Name, [string]$Command, [hashtable]$EnvVars)
44+
45+
$dir = Split-Path -Parent $Path
46+
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Force -Path $dir | Out-Null }
47+
48+
if (Test-Path $Path) {
49+
Copy-Item $Path "$Path.bak" -Force
50+
$raw = Get-Content -Raw -Path $Path
51+
if ([string]::IsNullOrWhiteSpace($raw)) {
52+
$config = [pscustomobject]@{}
53+
} else {
54+
$config = $raw | ConvertFrom-Json
55+
}
56+
} else {
57+
$config = [pscustomobject]@{}
58+
}
59+
60+
if (-not ($config.PSObject.Properties.Name -contains 'mcpServers')) {
61+
$config | Add-Member -NotePropertyName 'mcpServers' -NotePropertyValue ([pscustomobject]@{}) -Force
62+
}
63+
64+
$envObj = [pscustomobject]@{}
65+
foreach ($k in $EnvVars.Keys) {
66+
$envObj | Add-Member -NotePropertyName $k -NotePropertyValue $EnvVars[$k] -Force
67+
}
68+
69+
$serverEntry = [pscustomobject]@{ command = $Command; env = $envObj }
70+
$config.mcpServers | Add-Member -NotePropertyName $Name -NotePropertyValue $serverEntry -Force
71+
72+
$json = $config | ConvertTo-Json -Depth 100
73+
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
74+
[System.IO.File]::WriteAllText($Path, $json, $utf8NoBom)
75+
}
76+
77+
Write-Host "TestOps MCP installer" -ForegroundColor White
78+
79+
# --- 1. Detect platform ---------------------------------------------------
80+
Write-Step "Detecting platform"
81+
$arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'ARM64') { 'arm64' } else { 'amd64' }
82+
$asset = "testops-mcp-windows-$arch.exe"
83+
Write-Ok "windows / $arch -> $asset"
84+
85+
# --- 2. Download binary ----------------------------------------------------
86+
Write-Step "Downloading binary ($Version)"
87+
if ($Version -eq "latest") {
88+
$url = "https://github.com/$Repo/releases/latest/download/$asset"
89+
} else {
90+
$url = "https://github.com/$Repo/releases/download/$Version/$asset"
91+
}
92+
93+
$installDir = Join-Path $env:LOCALAPPDATA "TestOpsMCP"
94+
if (-not (Test-Path $installDir)) { New-Item -ItemType Directory -Force -Path $installDir | Out-Null }
95+
$binPath = Join-Path $installDir "testops-mcp.exe"
96+
97+
try {
98+
Invoke-WebRequest -Uri $url -OutFile $binPath -UseBasicParsing
99+
} catch {
100+
throw "Download failed from $url`n$($_.Exception.Message)`nCheck the version tag or download manually from https://github.com/$Repo/releases"
101+
}
102+
if (-not (Test-Path $binPath) -or (Get-Item $binPath).Length -eq 0) {
103+
throw "Downloaded file is empty: $binPath"
104+
}
105+
Write-Ok "saved to $binPath"
106+
107+
# --- 3. Collect Allure credentials ----------------------------------------
108+
Write-Step "Allure TestOps credentials"
109+
if (-not $AllureBaseUrl) {
110+
$AllureBaseUrl = Read-Host "Allure TestOps URL (e.g. https://your-testops.com)"
111+
}
112+
$AllureBaseUrl = $AllureBaseUrl.Trim().TrimEnd('/')
113+
if ($AllureBaseUrl -notmatch '^https?://') { $AllureBaseUrl = "https://$AllureBaseUrl" }
114+
115+
if (-not $AllureToken) {
116+
$sec = Read-Host "Allure API token (input hidden)" -AsSecureString
117+
$AllureToken = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
118+
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec))
119+
}
120+
$AllureToken = $AllureToken.Trim()
121+
if (-not $AllureBaseUrl -or -not $AllureToken) { throw "Both URL and token are required." }
122+
Write-Ok "URL: $AllureBaseUrl"
123+
124+
$envVars = @{ ALLURE_BASE_URL = $AllureBaseUrl; ALLURE_TOKEN = $AllureToken }
125+
126+
# --- 4. Claude Desktop -----------------------------------------------------
127+
if (-not $NoClaudeDesktop) {
128+
Write-Step "Configuring Claude Desktop"
129+
$desktopCfg = Join-Path $env:APPDATA "Claude\claude_desktop_config.json"
130+
Update-DesktopConfig -Path $desktopCfg -Name $ServerName -Command $binPath -EnvVars $envVars
131+
Write-Ok "updated $desktopCfg"
132+
}
133+
134+
# --- 5. Claude Code (CLI) --------------------------------------------------
135+
if (-not $NoClaudeCode) {
136+
Write-Step "Configuring Claude Code"
137+
$claude = Get-Command claude -ErrorAction SilentlyContinue
138+
if ($claude) {
139+
& claude mcp remove -s user $ServerName *> $null
140+
& claude mcp add -s user $ServerName $binPath `
141+
-e "ALLURE_BASE_URL=$AllureBaseUrl" `
142+
-e "ALLURE_TOKEN=$AllureToken"
143+
if ($LASTEXITCODE -eq 0) { Write-Ok "registered '$ServerName' in Claude Code (user scope)" }
144+
else { Write-Warn2 "claude CLI returned exit code $LASTEXITCODE" }
145+
} else {
146+
Write-Warn2 "claude CLI not found on PATH — skipped. Run this later if you use Claude Code:"
147+
Write-Host " claude mcp add -s user $ServerName `"$binPath`" -e ALLURE_BASE_URL=$AllureBaseUrl -e ALLURE_TOKEN=<token>"
148+
}
149+
}
150+
151+
# --- Done ------------------------------------------------------------------
152+
Write-Host "`nDone." -ForegroundColor Green
153+
Write-Host " * Claude Desktop: fully restart it (quit from the tray, not just close the window)."
154+
Write-Host " * Then ask Claude: `"List all projects in Allure`""

install.sh

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#!/usr/bin/env bash
2+
#
3+
# One-shot installer for the TestOps MCP server (per-user / stdio mode).
4+
#
5+
# Downloads the right binary for your OS/arch from GitHub Releases, asks for your
6+
# Allure TestOps URL + API token, and registers the server in BOTH:
7+
# * Claude Desktop (claude_desktop_config.json)
8+
# * Claude Code (via `claude mcp add -s user`, if the CLI is installed)
9+
#
10+
# Re-running the script is safe — it overwrites the existing "testops" entry.
11+
#
12+
# Usage:
13+
# Interactive: ./install.sh
14+
# Non-interactive: ALLURE_BASE_URL=https://your-testops.com ALLURE_TOKEN=xxx ./install.sh
15+
# Pin a version: VERSION=v2.0.3 ./install.sh
16+
#
17+
set -euo pipefail
18+
19+
REPO="MimoJanra/TestOpsMCP"
20+
VERSION="${VERSION:-latest}"
21+
SERVER_NAME="${SERVER_NAME:-testops}"
22+
23+
c_cyan() { printf '\033[36m%s\033[0m\n' "$1"; }
24+
c_green() { printf '\033[32m%s\033[0m\n' "$1"; }
25+
c_yellow() { printf '\033[33m%s\033[0m\n' "$1"; }
26+
step() { printf '\n'; c_cyan "==> $1"; }
27+
ok() { c_green " OK $1"; }
28+
warn() { c_yellow " ! $1"; }
29+
die() { printf '\033[31mError: %s\033[0m\n' "$1" >&2; exit 1; }
30+
31+
echo "TestOps MCP installer"
32+
33+
# --- 1. Detect platform ----------------------------------------------------
34+
step "Detecting platform"
35+
case "$(uname -s)" in
36+
Darwin) PLAT="macos" ;;
37+
Linux) PLAT="linux" ;;
38+
*) die "Unsupported OS: $(uname -s). Use install.ps1 on Windows." ;;
39+
esac
40+
case "$(uname -m)" in
41+
x86_64|amd64) ARCH="amd64" ;;
42+
arm64|aarch64) ARCH="arm64" ;;
43+
*) die "Unsupported CPU arch: $(uname -m)" ;;
44+
esac
45+
ASSET="testops-mcp-${PLAT}-${ARCH}"
46+
ok "${PLAT} / ${ARCH} -> ${ASSET}"
47+
48+
# --- 2. Download binary -----------------------------------------------------
49+
step "Downloading binary (${VERSION})"
50+
if [ "$VERSION" = "latest" ]; then
51+
URL="https://github.com/${REPO}/releases/latest/download/${ASSET}"
52+
else
53+
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ASSET}"
54+
fi
55+
56+
INSTALL_DIR="$HOME/.testops-mcp"
57+
mkdir -p "$INSTALL_DIR"
58+
BIN="$INSTALL_DIR/testops-mcp"
59+
60+
if command -v curl >/dev/null 2>&1; then
61+
curl -fsSL "$URL" -o "$BIN" || die "Download failed from $URL — check the version tag or download manually from https://github.com/${REPO}/releases"
62+
elif command -v wget >/dev/null 2>&1; then
63+
wget -qO "$BIN" "$URL" || die "Download failed from $URL"
64+
else
65+
die "Neither curl nor wget found. Install one and retry."
66+
fi
67+
[ -s "$BIN" ] || die "Downloaded file is empty: $BIN"
68+
chmod +x "$BIN"
69+
ok "saved to $BIN"
70+
71+
# --- 3. Collect Allure credentials -----------------------------------------
72+
step "Allure TestOps credentials"
73+
if [ -z "${ALLURE_BASE_URL:-}" ]; then
74+
read -r -p "Allure TestOps URL (e.g. https://your-testops.com): " ALLURE_BASE_URL
75+
fi
76+
ALLURE_BASE_URL="${ALLURE_BASE_URL%/}"
77+
case "$ALLURE_BASE_URL" in
78+
http://*|https://*) ;;
79+
*) ALLURE_BASE_URL="https://$ALLURE_BASE_URL" ;;
80+
esac
81+
if [ -z "${ALLURE_TOKEN:-}" ]; then
82+
read -r -s -p "Allure API token (input hidden): " ALLURE_TOKEN
83+
echo
84+
fi
85+
[ -n "$ALLURE_BASE_URL" ] && [ -n "$ALLURE_TOKEN" ] || die "Both URL and token are required."
86+
ok "URL: $ALLURE_BASE_URL"
87+
88+
# --- 4. Claude Desktop ------------------------------------------------------
89+
if [ "$PLAT" = "macos" ]; then
90+
DESKTOP_CFG="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
91+
else
92+
DESKTOP_CFG="${XDG_CONFIG_HOME:-$HOME/.config}/Claude/claude_desktop_config.json"
93+
fi
94+
95+
write_desktop_config() {
96+
local path="$1"
97+
mkdir -p "$(dirname "$path")"
98+
[ -f "$path" ] && cp "$path" "$path.bak"
99+
100+
if command -v python3 >/dev/null 2>&1; then
101+
CFG_PATH="$path" SRV_NAME="$SERVER_NAME" SRV_CMD="$BIN" \
102+
A_URL="$ALLURE_BASE_URL" A_TOK="$ALLURE_TOKEN" python3 - <<'PY'
103+
import json, os
104+
path = os.environ['CFG_PATH']
105+
try:
106+
with open(path) as f:
107+
cfg = json.load(f)
108+
if not isinstance(cfg, dict):
109+
cfg = {}
110+
except (FileNotFoundError, ValueError):
111+
cfg = {}
112+
cfg.setdefault('mcpServers', {})
113+
cfg['mcpServers'][os.environ['SRV_NAME']] = {
114+
'command': os.environ['SRV_CMD'],
115+
'env': {
116+
'ALLURE_BASE_URL': os.environ['A_URL'],
117+
'ALLURE_TOKEN': os.environ['A_TOK'],
118+
},
119+
}
120+
with open(path, 'w') as f:
121+
json.dump(cfg, f, indent=2)
122+
f.write('\n')
123+
PY
124+
return 0
125+
fi
126+
127+
if command -v jq >/dev/null 2>&1; then
128+
[ -f "$path" ] || echo '{}' > "$path"
129+
local tmp; tmp="$(mktemp)"
130+
jq --arg n "$SERVER_NAME" --arg c "$BIN" --arg u "$ALLURE_BASE_URL" --arg t "$ALLURE_TOKEN" \
131+
'.mcpServers[$n] = {command:$c, env:{ALLURE_BASE_URL:$u, ALLURE_TOKEN:$t}}' \
132+
"$path" > "$tmp" && mv "$tmp" "$path"
133+
return 0
134+
fi
135+
136+
return 1
137+
}
138+
139+
step "Configuring Claude Desktop"
140+
if write_desktop_config "$DESKTOP_CFG"; then
141+
ok "updated $DESKTOP_CFG"
142+
else
143+
warn "Neither python3 nor jq found — cannot safely merge JSON."
144+
warn "Add this to mcpServers in $DESKTOP_CFG manually:"
145+
cat <<EOF
146+
"$SERVER_NAME": {
147+
"command": "$BIN",
148+
"env": { "ALLURE_BASE_URL": "$ALLURE_BASE_URL", "ALLURE_TOKEN": "<token>" }
149+
}
150+
EOF
151+
fi
152+
153+
# --- 5. Claude Code (CLI) ---------------------------------------------------
154+
step "Configuring Claude Code"
155+
if command -v claude >/dev/null 2>&1; then
156+
claude mcp remove -s user "$SERVER_NAME" >/dev/null 2>&1 || true
157+
claude mcp add -s user "$SERVER_NAME" "$BIN" \
158+
-e "ALLURE_BASE_URL=$ALLURE_BASE_URL" \
159+
-e "ALLURE_TOKEN=$ALLURE_TOKEN"
160+
ok "registered '$SERVER_NAME' in Claude Code (user scope)"
161+
else
162+
warn "claude CLI not found on PATH — skipped. Run this later if you use Claude Code:"
163+
echo " claude mcp add -s user $SERVER_NAME \"$BIN\" -e ALLURE_BASE_URL=$ALLURE_BASE_URL -e ALLURE_TOKEN=<token>"
164+
fi
165+
166+
# --- Done -------------------------------------------------------------------
167+
c_green "\nDone."
168+
echo " * Claude Desktop: fully quit and reopen it."
169+
echo " * Then ask Claude: \"List all projects in Allure\""

0 commit comments

Comments
 (0)