MCP Installation on Windows

MCP Installation on Windows

ℹ️

Starting with Claude Desktop 0.78 this is no longer necessary.

Install a recent version of node.js (18.0+), and configure claude_desktop_config.json as below:

  "mcpServers": {
    "mcp-webcam": {
      "command": "npx",
      "args": [
        "-y",
        "@llmindset/mcp-webcam"
      ]
    }
  },
  ...
  ...

This PowerShell script installs node.js MCP Servers on Windows, to work around the issues with using nvm and npx. This will work for node.js packages listed on mcp-get.

Basic usage is to open PowerShell, and run the script like below:

.\mcp-install.ps1 @llmindset/mcp-hfspace

Download from here, copy-and-paste from below, or from this gist.

On older versions of PowerShell you may need to run Set-ExecutionPolicy Bypass -Scope Process before this script.

⚠️
Only install MCP Servers from trusted sources. Never add commands to your claude_desktop_config.json file unless you fully understand them.

Note - this doesn’t keep the Package automatically up-to-date. Use npm install –global @packagename to force an update.

param(
    [Parameter(Mandatory=$true)]
    [string]$PackageName
)

Write-Host "Starting installation process for $PackageName..."

# Check Claude Desktop folder
Write-Host "Checking Claude Desktop installation..."
$claudeFolder = Join-Path $env:APPDATA "Claude"
if (-not (Test-Path $claudeFolder)) {
    Write-Host "Claude Desktop is not installed. Please install from https://claude.ai/download"
    exit 1
}

# Check Node.js version
Write-Host "Checking Node.js version..."
try {
    $nodeVersion = node --version
    if ($nodeVersion -notmatch '^v\d+\.\d+\.\d+$') {
        throw "Invalid version format"
    }
    $majorVersion = [int]($nodeVersion.Substring(1).Split('.')[0])
    if ($majorVersion -lt 16) {
        Write-Host "Node.js version 16 or higher is required. Please install from https://nodejs.org/en/download/prebuilt-installer"
        exit 1
    }
} catch {
    Write-Host "Node.js is not installed or not in PATH. Please install from https://nodejs.org/en/download/prebuilt-installer"
    exit 1
}

# Check if package exists on NPM
Write-Host "Checking if package exists on NPM..."
try {
    $npmViewOutput = npm view $PackageName
    if ($LASTEXITCODE -ne 0) {
        Write-Host "Package '$PackageName' is not available on NPM. Please verify the package name."
        exit 1
    }
} catch {
    Write-Host "Package '$PackageName' is not available on NPM. Please verify the package name."
    exit 1
}

# Install package globally
Write-Host "Installing $PackageName globally..."
try {
    npm install -g $PackageName
    if ($LASTEXITCODE -ne 0) {
        throw "npm install failed"
    }
} catch {
    Write-Host "Failed to install $PackageName. Error: $_"
    exit 1
}

# Get global package install path
Write-Host "Verifying Node.js global package path..."
try {
    $globalPath = npm root -g
    if (-not (Test-Path $globalPath)) {
        Write-Host "Node.js global package path does not exist. Node.js is not correctly configured."
        exit 1
    }
} catch {
    Write-Host "Failed to get Node.js global package path. Node.js is not correctly configured."
    exit 1
}

# Get package.json and find entry point
Write-Host "Reading package configuration..."
$packagePath = Join-Path $globalPath $PackageName
$packageJsonPath = Join-Path $packagePath "package.json"
if (-not (Test-Path $packageJsonPath)) {
    Write-Host "package.json not found at: $packageJsonPath"
    exit 1
}

try {
    $packageJson = Get-Content $packageJsonPath | ConvertFrom-Json
    if (-not $packageJson.bin) {
        Write-Host "Package does not have a 'bin' field in package.json"
        exit 1
    }

    # Handle both string and object bin fields
    $binPath = if ($packageJson.bin -is [System.String]) {
        $packageJson.bin
    } else {
        $binValues = @($packageJson.bin.PSObject.Properties.Value)
        if ($binValues.Count -eq 0) {
            Write-Host "No binary paths found in package.json"
            exit 1
        }
        $binValues[0]  # Take the first binary path
    }

    $entryPoint = Join-Path $packagePath $binPath
    if (-not (Test-Path $entryPoint)) {
        Write-Host "Entry point not found at: $entryPoint"
        exit 1
    }
} catch {
    Write-Host "Failed to read or parse package.json. Error: $_"
    exit 1
}


# Check/create config file
$configFile = Join-Path $claudeFolder "claude_desktop_config.json"
if (-not (Test-Path $configFile)) {
    Write-Host "Creating Claude Desktop configuration file..."
    $initialConfig = @{
        mcpServers = @{}
    }
    $initialConfig | ConvertTo-Json | Set-Content $configFile
}

# Read current config
Write-Host "Updating Claude Desktop configuration..."
try {
    $config = Get-Content $configFile | ConvertFrom-Json
    $serverName = $PackageName.Split('/')[-1]

    # Check if server already exists
    if ($config.mcpServers.PSObject.Properties.Name -contains $serverName) {
        Write-Host "Server '$serverName' is already installed in Claude Desktop configuration."
        exit 1
    }

    # Add new server configuration
    $newServer = @{
        command = "node"
        args = @($entryPoint)
    }
    
    # Convert to JSON, update, and save
    $config.mcpServers | Add-Member -MemberType NoteProperty -Name $serverName -Value $newServer
    $config | ConvertTo-Json -Depth 10 | Set-Content $configFile

    Write-Host "Installation complete! Please restart Claude Desktop for changes to take effect."
} catch {
    Write-Host "Failed to update configuration file. Error: $_"
    exit 1
}