# FedMCP Installer for Claude Desktop (Windows)
# Usage: irm https://raw.githubusercontent.com/northernvariables/CanadaGPT/main/packages/fedmcp/scripts/install-claude-desktop.ps1 | iex
#
# For macOS/Linux, use: curl -fsSL https://raw.githubusercontent.com/northernvariables/CanadaGPT/main/packages/fedmcp/scripts/install-claude-desktop.sh | bash
$ErrorActionPreference = "Stop"
# ============================================================================
# Configuration
# ============================================================================
$FEDMCP_REPO = "https://github.com/northernvariables/CanadaGPT.git"
$FEDMCP_INSTALL_DIR = "$env:USERPROFILE\.fedmcp"
$FEDMCP_VENV = "$FEDMCP_INSTALL_DIR\venv"
$CONFIG_DIR = "$env:APPDATA\Claude"
$CONFIG_FILE = "$CONFIG_DIR\claude_desktop_config.json"
# ============================================================================
# Helper Functions
# ============================================================================
function Write-Info { param($msg) Write-Host "i " -ForegroundColor Blue -NoNewline; Write-Host $msg }
function Write-Success { param($msg) Write-Host "✓ " -ForegroundColor Green -NoNewline; Write-Host $msg }
function Write-Warn { param($msg) Write-Host "⚠ " -ForegroundColor Yellow -NoNewline; Write-Host $msg }
function Write-Err { param($msg) Write-Host "✗ " -ForegroundColor Red -NoNewline; Write-Host $msg }
function Exit-WithError {
param($msg)
Write-Err $msg
Write-Host ""
Write-Err "For help, visit: https://github.com/northernvariables/CanadaGPT/issues"
exit 1
}
# ============================================================================
# Banner
# ============================================================================
Write-Host ""
Write-Host "╔═══════════════════════════════════════════════════════════════╗" -ForegroundColor Blue
Write-Host "║ 🍁 FedMCP Desktop Installer ║" -ForegroundColor Blue
Write-Host "║ Canadian Federal Government Data for Claude Desktop ║" -ForegroundColor Blue
Write-Host "╚═══════════════════════════════════════════════════════════════╝" -ForegroundColor Blue
Write-Host ""
# ============================================================================
# Dependency Checks
# ============================================================================
Write-Info "Checking dependencies..."
# Check Python - try 'py' launcher first (standard on Windows), then 'python'
$pythonCmd = $null
$pythonVersion = $null
if (Get-Command "py" -ErrorAction SilentlyContinue) {
try {
$pythonVersion = & py -3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>$null
if ($pythonVersion) { $pythonCmd = "py" }
} catch {}
}
if (-not $pythonCmd -and (Get-Command "python" -ErrorAction SilentlyContinue)) {
try {
$pythonVersion = & python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>$null
if ($pythonVersion) { $pythonCmd = "python" }
} catch {}
}
if (-not $pythonCmd) {
Exit-WithError "Python not found. Install from https://www.python.org/downloads/"
}
# Check version
$versionParts = $pythonVersion -split '\.'
$major = [int]$versionParts[0]
$minor = [int]$versionParts[1]
if ($major -lt 3 -or ($major -eq 3 -and $minor -lt 10)) {
Exit-WithError "Python 3.10+ required (found $pythonVersion). Please upgrade."
}
Write-Success "Python $pythonVersion"
# Check git
if (-not (Get-Command "git" -ErrorAction SilentlyContinue)) {
Exit-WithError "git not found. Install from https://git-scm.com/download/win"
}
$gitVersion = (git --version) -replace 'git version ', ''
Write-Success "git $gitVersion"
Write-Host ""
# ============================================================================
# Installation
# ============================================================================
Write-Info "Installing FedMCP..."
# Create install directory
if (-not (Test-Path $FEDMCP_INSTALL_DIR)) {
New-Item -ItemType Directory -Path $FEDMCP_INSTALL_DIR -Force | Out-Null
}
# Check if pipx is available
$usePipx = $false
if (Get-Command "pipx" -ErrorAction SilentlyContinue) {
Write-Info "Using pipx (recommended)..."
try {
pipx uninstall fedmcp 2>$null
} catch {}
pipx install "git+$FEDMCP_REPO#subdirectory=packages/fedmcp"
# Find pipx venv path
$pipxVenvs = & pipx environment --value PIPX_LOCAL_VENVS 2>$null
if (-not $pipxVenvs) { $pipxVenvs = "$env:USERPROFILE\.local\pipx\venvs" }
$PYTHON_PATH = "$pipxVenvs\fedmcp\Scripts\python.exe"
if (Test-Path $PYTHON_PATH) {
$usePipx = $true
} else {
Write-Warn "Could not locate pipx venv, falling back to venv"
}
}
if (-not $usePipx) {
Write-Info "Creating virtual environment at $FEDMCP_VENV..."
# Remove existing for clean install
if (Test-Path $FEDMCP_VENV) {
Write-Info "Removing existing installation for clean upgrade..."
Remove-Item -Recurse -Force $FEDMCP_VENV
}
# Create venv
if ($pythonCmd -eq "py") {
& py -3 -m venv $FEDMCP_VENV
} else {
& python -m venv $FEDMCP_VENV
}
# Upgrade pip
& "$FEDMCP_VENV\Scripts\pip.exe" install --upgrade pip --quiet 2>$null
# Install fedmcp
Write-Info "Installing fedmcp package (this may take a minute)..."
& "$FEDMCP_VENV\Scripts\pip.exe" install "git+$FEDMCP_REPO#subdirectory=packages/fedmcp"
$PYTHON_PATH = "$FEDMCP_VENV\Scripts\python.exe"
}
Write-Success "FedMCP installed"
Write-Host ""
# ============================================================================
# Verification
# ============================================================================
Write-Info "Verifying installation..."
if (-not (Test-Path $PYTHON_PATH)) {
Exit-WithError "Python executable not found at: $PYTHON_PATH"
}
try {
& $PYTHON_PATH -c "import fedmcp" 2>$null
if ($LASTEXITCODE -ne 0) { throw "Import failed" }
} catch {
Exit-WithError "Verification failed: fedmcp module not importable."
}
$installedVersion = & $PYTHON_PATH -c "import fedmcp; print(getattr(fedmcp, '__version__', 'installed'))" 2>$null
Write-Success "FedMCP $installedVersion verified"
Write-Host ""
# ============================================================================
# Claude Desktop Configuration
# ============================================================================
Write-Info "Configuring Claude Desktop..."
# Create config directory
if (-not (Test-Path $CONFIG_DIR)) {
New-Item -ItemType Directory -Path $CONFIG_DIR -Force | Out-Null
}
# Backup existing config
if (Test-Path $CONFIG_FILE) {
$backupFile = "$CONFIG_FILE.backup.$(Get-Date -Format 'yyyyMMddHHmmss')"
Copy-Item $CONFIG_FILE $backupFile
Write-Info "Backed up existing config to: $(Split-Path $backupFile -Leaf)"
}
# Use Python to safely update config
$pythonScript = @"
import json
import sys
import os
config_file = r'$CONFIG_FILE'
python_path = r'$PYTHON_PATH'
fedmcp_config = {
"command": python_path,
"args": ["-m", "fedmcp.server"]
}
config = {}
if os.path.exists(config_file):
try:
with open(config_file, 'r', encoding='utf-8') as f:
content = f.read().strip()
if content:
config = json.loads(content)
except json.JSONDecodeError:
print("Warning: Existing config was malformed, creating fresh", file=sys.stderr)
config = {}
except Exception as e:
print(f"Warning: Could not read config: {e}", file=sys.stderr)
config = {}
if not isinstance(config.get('mcpServers'), dict):
config['mcpServers'] = {}
config['mcpServers']['fedmcp'] = fedmcp_config
temp_file = config_file + '.tmp'
try:
with open(temp_file, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2)
f.write('\n')
with open(temp_file, 'r', encoding='utf-8') as f:
json.load(f)
os.replace(temp_file, config_file)
except Exception as e:
if os.path.exists(temp_file):
os.remove(temp_file)
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
"@
& $PYTHON_PATH -c $pythonScript
if ($LASTEXITCODE -ne 0) {
Exit-WithError "Failed to configure Claude Desktop"
}
Write-Success "Claude Desktop configured"
Write-Info "Config: $CONFIG_FILE"
Write-Host ""
# ============================================================================
# Success Message
# ============================================================================
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Green
Write-Host " 🎉 Installation Complete! 🎉" -ForegroundColor Green
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Green
Write-Host ""
Write-Host "▶ Next step: Quit and reopen Claude Desktop" -ForegroundColor Yellow
Write-Host ""
Write-Host "FedMCP gives Claude access to 75+ tools for Canadian government data:"
Write-Host " • Parliamentary debates (Hansard)"
Write-Host " • MP voting records and expenses"
Write-Host " • Bill tracking and legislative analysis"
Write-Host " • Lobbying registrations"
Write-Host " • Federal contracts and spending"
Write-Host ""
Write-Host "Example prompts to try:" -ForegroundColor Blue
Write-Host ' "What bills are currently being debated in Parliament?"'
Write-Host ' "Show me Pierre Poilievre''s voting record"'
Write-Host ' "Who is lobbying on artificial intelligence?"'
Write-Host ""
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Yellow
Write-Host "Optional: Add API keys for higher rate limits" -ForegroundColor Yellow
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Yellow
Write-Host ""
Write-Host "Edit $CONFIG_FILE and add an `"env`" block:"
Write-Host ""
Write-Host ' "fedmcp": {'
Write-Host ' "command": "...",'
Write-Host ' "args": ["-m", "fedmcp.server"],'
Write-Host ' "env": {'
Write-Host ' "FEDMCP_API_KEY": "your-canadagpt-pro-key"'
Write-Host ' }'
Write-Host ' }'
Write-Host ""
Write-Host "Get keys at:"
Write-Host " • CanadaGPT PRO (10k req/hr): https://canadagpt.ca/settings"
Write-Host " • CanLII (legal search): https://canlii.org/en/feedback/feedback.html"
Write-Host ""