# Builds a Cursor MCP install deeplink from a server name and config object (hashtable/JSON). # Usage: . scripts\cursor-deeplink.ps1; New-CursorDeeplink -Name wordcraft -Config @{ command='...'; args=@(...) } # Or: scripts\cursor-deeplink.ps1 -Name wordcraft -ConfigJson '{...}' param( [string]$Name, [string]$ConfigJson ) . (Join-Path $PSScriptRoot 'lib.ps1') function New-CursorDeeplink([string]$ServerName, $Config) { # Config = server transport object (command/args/...) OR { serverName = transport }. # Deeplink uses name= + base64(JSON of the transport object keyed by name), per Cursor docs. if ($Config -is [string]) { $obj = $Config | ConvertFrom-Json } else { $obj = $Config } # Normalize to { name: transport } $props = @($obj.PSObject.Properties.Name) if ($props.Count -eq 1 -and $props[0] -eq $ServerName) { $payload = $obj } elseif ($obj.command -or $obj.PSObject.Properties['command']) { $payload = @{ $ServerName = $obj } } else { $payload = $obj } $json = ($payload | ConvertTo-Json -Compress -Depth 20) $bytes = $Utf8NoBom.GetBytes($json) $b64 = [Convert]::ToBase64String($bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_') return "cursor://anysphere.cursor-deeplink/mcp/install?name=$([Uri]::EscapeDataString($ServerName))&config=$b64" } if ($Name -and $ConfigJson) { Write-Output (New-CursorDeeplink -ServerName $Name -Config $ConfigJson) }