@@ -4,7 +4,6 @@
WSL2 + Claude Code CLI + Unity MCP + Rust Token Killer 全栈一键部署脚本
. DESCRIPTION
自动完成以下步骤:
0 . 检测 v2rayN 代理端口,配置 Windows & WSL2 两侧代理
1 . 启用 WSL2 功能 & 安装 Ubuntu 发行版
2 . 检测/安装 Windows 本机 Node . js( AI 客户端 MCP 需要)
3 . WSL2 内安装 Node . js LTS( Claude Code CLI 需要)
@@ -13,8 +12,6 @@
6 . 配置 Windows 防火墙放行 MCP Bridge 端口
7 . 安装 Rust 工具链 & Token Killer (rtk)
8 . 写入 PowerShell Profile 快捷命令
. PARAMETER ProxyPort
v2rayN HTTP 代理端口; 0 = 自动检测;-1 = 跳过代理
. PARAMETER BridgePort
Unity MCP Bridge 端口,默认 7890
. PARAMETER InstallDir
@@ -30,7 +27,6 @@
已有 WSL2 可普通终端运行,加 -SkipWSL 跳过 WSL2 安装检查。
#>
param (
[ int ] $ProxyPort = 0 ,
[ int ] $BridgePort = 7890 ,
[ string ] $InstallDir = " $env:USERPROFILE \unity-mcp-server " ,
[ string ] $UnityHubPath = " C:\Program Files\Unity Hub\Unity Hub.exe " ,
@@ -78,108 +74,25 @@ if (Test-Path $EnvFile) {
}
$ANTHROPIC_API_KEY = if ( $Config [ " ANTHROPIC_API_KEY " ] ) { $Config [ " ANTHROPIC_API_KEY " ] } else { " " }
$ANTHROPIC_BASE_URL = if ( $Config [ " ANTHROPIC_BASE_URL " ] ) { $Config [ " ANTHROPIC_BASE_URL " ] } else { " https://api.anthropic.com " }
$CLAUDE_MODEL = if ( $Config [ " CLAUDE_MODE L" ] ) { $Config [ " CLAUDE_MODE L" ] } else { " claude-opus-4-5 " }
$ANTHROPIC_AUTH_TOKEN = if ( $Config [ " ANTHROPIC_AUTH_TOKEN " ] ) { $Config [ " ANTHROPIC_AUTH_TOKEN " ] } else { " " }
$ANTHROPIC_BASE_URL = if ( $Config [ " ANTHROPIC_BASE_UR L" ] ) { $Config [ " ANTHROPIC_BASE_UR L" ] } else { " https://api.lmuai.com " }
$CLAUDE_MODEL = if ( $Config [ " CLAUDE_MODEL " ] ) { $Config [ " CLAUDE_MODEL " ] } else { " claude-sonnet-4-6 " }
$WSL_DISTRO = if ( $Config [ " WSL_DISTRO " ] ) { $Config [ " WSL_DISTRO " ] } else { " Ubuntu " }
$SKIP_WSL_INSTALL = if ( $Config [ " SKIP_WSL_INSTALL " ] ) { $Config [ " SKIP_WSL_INSTALL " ] } else { " false " }
# 判断认证方式:灵眸/中转用 AUTH_TOKEN, 官方用 API_KEY
$UseLmuAuth = ( $ANTHROPIC_AUTH_TOKEN -ne " " -and $ANTHROPIC_BASE_URL -ne " https://api.anthropic.com " )
# ──────────────────────────────────────────────────────────────
# Banner
# ──────────────────────────────────────────────────────────────
Write-Host " "
Write-Host " ╔══════════════════════════════════════════════════════════╗ " -ForegroundColor Cyan
Write-Host " ║ WSL2 + Claude Code CLI + Unity MCP + RTK 全栈部署 ║ " -ForegroundColor Cyan
Write-Host " ║ AnkleBreaker Unity MCP · v2rayN 代理自动检测 ║ " -ForegroundColor Cyan
Write-Host " ║ AnkleBreaker Unity MCP · WSL2 Mirror Mode ║ " -ForegroundColor Cyan
Write-Host " ╚══════════════════════════════════════════════════════════╝ " -ForegroundColor Cyan
Write-Host " "
# ══════════════════════════════════════════════════════════════
# Step 0: v2rayN 代理检测与配置
# ══════════════════════════════════════════════════════════════
Write-Step " 0/8 v2rayN 代理检测 "
# ── 检测代理端口 ──────────────────────────────────────────────
function Get-V2RayNProxyPort {
# 1. Windows 系统代理注册表( v2rayN"设为系统代理"时写入)
try {
$ie = Get-ItemProperty `
" HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings " `
-ErrorAction SilentlyContinue
if ( $ie . ProxyEnable -eq 1 -and $ie . ProxyServer -match " :(\d+) " ) {
return [ int ] $Matches [ 1 ]
}
} catch { }
# 2. v2rayN 配置文件
$cfgPaths = @ (
" $env:APPDATA \v2rayN\guiNConfig.json " ,
" $env:LOCALAPPDATA \v2rayN\guiNConfig.json "
)
foreach ( $p in $cfgPaths ) {
if ( Test-Path $p ) {
try {
$j = Get-Content $p -Raw | ConvertFrom-Json
if ( $j . localPort ) { return [ int ] $j . localPort }
if ( $j . httpPort ) { return [ int ] $j . httpPort }
} catch { }
}
}
# 3. 探测常用端口
foreach ( $port in @ ( 10809 , 10808 , 7890 , 1080 , 8080 ) ) {
try {
$tcp = New-Object System . Net . Sockets . TcpClient
$ar = $tcp . BeginConnect ( " 127.0.0.1 " , $port , $null , $null )
if ( $ar . AsyncWaitHandle . WaitOne ( 300 , $false ) ) {
$tcp . EndConnect ( $ar ) ; $tcp . Close ( ) ; return $port
}
$tcp . Close ( )
} catch { }
}
return 0
}
function Set-WindowsProxy {
param ( [ int ] $Port )
$url = " http://127.0.0.1: $Port "
git config - -global http . proxy $url 2 > $null
git config - -global https . proxy $url 2 > $null
& npm config set proxy $url - -location global 2 > $null
& npm config set https-proxy $url - -location global 2 > $null
$env:http_proxy = $url ; $env:https_proxy = $url
$env:HTTP_PROXY = $url ; $env:HTTPS_PROXY = $url
Write-OK " Windows git/npm/env 代理 -> $url "
}
function Clear-WindowsProxy {
git config - -global - -unset http . proxy 2 > $null
git config - -global - -unset https . proxy 2 > $null
& npm config delete proxy - -location global 2 > $null
& npm config delete https-proxy - -location global 2 > $null
" http_proxy " , " https_proxy " , " HTTP_PROXY " , " HTTPS_PROXY " |
ForEach-Object { Remove-Item " Env:\ $_ " -ErrorAction SilentlyContinue }
}
$resolvedProxyPort = 0
if ( $ProxyPort -eq -1 ) {
Write-Warn " 已跳过代理配置(-ProxyPort -1) "
} elseif ( $ProxyPort -gt 0 ) {
$resolvedProxyPort = $ProxyPort
Set-WindowsProxy -Port $resolvedProxyPort
Write-OK " 使用指定代理端口: $resolvedProxyPort "
} else {
$resolvedProxyPort = Get-V2RayNProxyPort
if ( $resolvedProxyPort -gt 0 ) {
Set-WindowsProxy -Port $resolvedProxyPort
Write-OK " 自动检测到 v2rayN 代理端口: $resolvedProxyPort "
} else {
Write-Warn " 未检测到活跃代理,将使用直连网络 "
Write-Warn " 如需代理,请指定: pwsh deploy.ps1 -ProxyPort 10809 "
Write-Warn " ⚠ 确保 v2rayN 已开启「允许来自局域网的连接」( WSL2 需要) "
}
}
# ══════════════════════════════════════════════════════════════
# Step 1: WSL2 安装
# ══════════════════════════════════════════════════════════════
@@ -291,39 +204,6 @@ if ($needRestart) {
Start-Sleep 3
}
# ── 配置 WSL2 侧代理(持久化到 ~/.bashrc) ───────────────────
if ( $resolvedProxyPort -gt 0 ) {
Write-Info " 配置 WSL2 代理(端口 $resolvedProxyPort ) ..."
# mirrored 模式下 127.0.0.1 即 Windows, 直接用即可
$proxyEnvContent = " # WSL2 mirrored networking: 127.0.0.1 = Windows host `n export http_proxy= `" http://127.0.0.1: $resolvedProxyPort `" `n export https_proxy= `" http://127.0.0.1: $resolvedProxyPort `" `n export HTTP_PROXY= `" http://127.0.0.1: $resolvedProxyPort `" `n export HTTPS_PROXY= `" http://127.0.0.1: $resolvedProxyPort `" `n export no_proxy= `" localhost,127.0.0.1,::1 `" `n "
$tmpFile = " $env:TEMP \mcp-proxy.env "
$bytes = [ System.Text.Encoding ] :: UTF8 . GetBytes ( $proxyEnvContent )
[ System.IO.File ] :: WriteAllBytes ( $tmpFile , $bytes )
Copy-Item $tmpFile " \\wsl.localhost\ $WSL_DISTRO \tmp\mcp-proxy-deploy.env " -Force 2 > $null
Invoke-WSL " cp /tmp/mcp-proxy-deploy.env ~/.mcp-proxy.env && chmod 644 ~/.mcp-proxy.env && echo OK " | Out-Null
# 写入 ~/.bashrc( 幂等)
Invoke-WSL @'
if ! grep -q 'mcp-proxy.env' ~/.bashrc 2>/dev/null; then
printf '\n# Unity MCP WSL2 proxy (generated by deploy.ps1)\n[ -f ~/.mcp-proxy.env ] && . ~/.mcp-proxy.env\n' >> ~/.bashrc
fi
# 立即应用代理并配置 git
. ~/.mcp-proxy.env 2>/dev/null || true
if [ -n "$http_proxy" ]; then
git config --global http.proxy "$http_proxy"
git config --global https.proxy "$https_proxy"
echo "WSL2 git proxy set: $http_proxy"
fi
true
'@ -IgnoreError | Out-Null
Write-OK " WSL2 代理已写入 ~/.mcp-proxy.env + ~/.bashrc "
Write-Warn " ⚠ 请确保 v2rayN 已开启「允许来自局域网的连接」! "
}
# ══════════════════════════════════════════════════════════════
# Step 2: Windows 本机 Node.js 检查( AI 客户端 MCP 需要)
# ══════════════════════════════════════════════════════════════
@@ -356,13 +236,6 @@ if ($winNode) {
}
}
# 对 Windows npm 设置代理
if ( $resolvedProxyPort -gt 0 -and ( Get-Command npm -ErrorAction SilentlyContinue ) ) {
$proxyUrl = " http://127.0.0.1: $resolvedProxyPort "
& npm config set proxy $proxyUrl - -location global 2 > $null
& npm config set https-proxy $proxyUrl - -location global 2 > $null
}
# ══════════════════════════════════════════════════════════════
# Step 3: WSL2 系统依赖 & Node.js
# ══════════════════════════════════════════════════════════════
@@ -385,7 +258,6 @@ if ($nodeVer -match "v\d+") {
} else {
Write-Info " 安装 WSL2 Node.js LTS (via nvm)... "
$installNodeCmd = @'
. ~/.mcp-proxy.env 2>/dev/null || true
export DEBIAN_FRONTEND=noninteractive
sudo apt-get install -y -qq curl ca-certificates 2>/dev/null
# 安装 nvm
@@ -437,7 +309,6 @@ if ($claudeVer -notmatch "MISSING") {
$installClaudeCmd = @'
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
. ~/.mcp-proxy.env 2>/dev/null || true
npm install -g @anthropic-ai/claude-code --quiet
which claude
claude --version
@@ -510,8 +381,23 @@ $mcpAllowedTools = @(
" mcp__unity-mcp__unity_list_instances " , " mcp__unity-mcp__unity_select_instance " ,
" mcp__unity-mcp__unity_get_project_context "
)
$claudeSettingsJson = [ ordered ] @ { model = $CLAUDE_MODEL ; allowedTools = $mcpAllowedTools } |
ConvertTo-Json -Depth 3
$claudeSettingsJson = if ( $UseLmuAuth ) {
# 灵眸 / 中转 API: 使用 env.ANTHROPIC_AUTH_TOKEN( 避免与 ANTHROPIC_API_KEY 冲突)
[ ordered ] @ {
env = [ ordered ] @ {
ANTHROPIC_BASE_URL = $ANTHROPIC_BASE_URL
ANTHROPIC_AUTH_TOKEN = $ANTHROPIC_AUTH_TOKEN
API_TIMEOUT_MS = " 3000000 "
CLAUDE_CODE_ATTRIBUTION_HEADER = " 0 "
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = " 1 "
}
model = $CLAUDE_MODEL
allowedTools = $mcpAllowedTools
} | ConvertTo-Json -Depth 4
} else {
# Anthropic 官方:使用 model + allowedTools, API Key 由环境变量注入
[ ordered ] @ { model = $CLAUDE_MODEL ; allowedTools = $mcpAllowedTools } | ConvertTo-Json -Depth 3
}
$writeClaudeSettingsCmd = @"
m k d i r - p ~ / . c l a u d e
c a t > ~ / . c l a u d e / s e t t i n g s . j s o n < < ' S E T T I N G S '
@@ -522,22 +408,38 @@ true
Invoke-WSL $writeClaudeSettingsCmd -IgnoreError | Out-Null
# 写入 bash 环境变量( WSL2 侧)
$profBlock = " "
if ( $ ANTHROPIC_API_KEY) { $profBlock + = " export ANTHROPIC_API_KEY=' $ANTHROPIC_API_KEY '\n " }
if ( $ANTHROPIC_BASE_URL ) { $profBlock + = " export ANTHROPIC_BASE_URL=' $ANTHROPIC_BASE_URL '\n " }
# 灵眸模式: auth token 已在 settings.json env 块中,清理旧 bashrc 变量避免冲突
# 官方模式:写入 ANTHROPIC_API_KEY 到 bashrc
$cleanOldVarsCmd = @'
sed -i '/ANTHROPIC_API_KEY/d' ~/.bashrc ~/.profile 2>/dev/null || true
sed -i '/ANTHROPIC_BASE_URL/d' ~/.bashrc ~/.profile 2>/dev/null || true
sed -i '/CLAUDE_MODEL/d' ~/.bashrc ~/.profile 2>/dev/null || true
sed -i '/# Claude Code CLI/d' ~/.bashrc ~/.profile 2>/dev/null || true
true
'@
Invoke-WSL $cleanOldVarsCmd -IgnoreError | Out-Null
if ( -not $UseLmuAuth -and $ANTHROPIC_API_KEY ) {
$profBlock = " export ANTHROPIC_API_KEY=' $ANTHROPIC_API_KEY '\n "
$profBlock + = " export ANTHROPIC_BASE_URL=' $ANTHROPIC_BASE_URL '\n "
$profBlock + = " export CLAUDE_MODEL=' $CLAUDE_MODEL '\n "
$addEnvCmd = @"
i f ! g r e p - q ' A N T H R O P I C _ A P I _ K E Y ' ~ / . b a s h r c 2 > / d e v / n u l l ; t h e n
p r i n t f ' \ n # C l a u d e C o d e C L I \ n $profBlock ' > > ~ / . b a s h r c
f i
t r u e
"@
Invoke-WSL $addEnvCmd -IgnoreError | Out-Null
}
# Windows 侧 Claude 配置
$claudeDir = " $env:USERPROFILE \.claude "
if ( -not ( Test-Path $claudeDir ) ) { New-Item -ItemType Directory -Path $claudeDir | Out-Null }
$claudeSettingsJson | Set-Content " $claudeDir \settings.json " -Encoding UTF8
if ( $ANTHROPIC_API_KEY ) {
if ( $UseLmuAuth ) {
# 灵眸: token 已在 settings.json 中,清除可能冲突的 Windows 用户级变量
[ System.Environment ] :: SetEnvironmentVariable ( " ANTHROPIC_API_KEY " , $null , " User " )
[ System.Environment ] :: SetEnvironmentVariable ( " ANTHROPIC_BASE_URL " , $null , " User " )
[ System.Environment ] :: SetEnvironmentVariable ( " CLAUDE_MODEL " , $null , " User " )
} elseif ( $ANTHROPIC_API_KEY ) {
[ System.Environment ] :: SetEnvironmentVariable ( " ANTHROPIC_API_KEY " , $ANTHROPIC_API_KEY , " User " )
[ System.Environment ] :: SetEnvironmentVariable ( " ANTHROPIC_BASE_URL " , $ANTHROPIC_BASE_URL , " User " )
[ System.Environment ] :: SetEnvironmentVariable ( " CLAUDE_MODEL " , $CLAUDE_MODEL , " User " )
@@ -577,7 +479,6 @@ $wslMcpDir = "~/.mcp-servers/unity-mcp-server"
$wslMcpCmd = @'
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
. ~/.mcp-proxy.env 2>/dev/null || true
mkdir -p $HOME/.mcp-servers
if [ -d $HOME/.mcp-servers/unity-mcp-server/.git ]; then
git -C $HOME/.mcp-servers/unity-mcp-server pull --quiet 2>/dev/null || true
@@ -665,7 +566,6 @@ Merge-McpConfig "$env:APPDATA\Code\User\mcp.json" $mcpEntry
$wslMcpCfgCmd = @"
e x p o r t N V M _ D I R = " ` $HOME / . n v m "
[ - s " ` $NVM_DIR / n v m . s h " ] & & . " ` $NVM_DIR / n v m . s h "
. ~ / . m c p - p r o x y . e n v 2 > / d e v / n u l l | | t r u e
# 先 移 除 旧 条 目 ( 幂 等 ) , 再 添 加
c l a u d e m c p r e m o v e u n i t y - m c p - - s c o p e u s e r 2 > / d e v / n u l l | | t r u e
c l a u d e m c p a d d - - s c o p e u s e r u n i t y - m c p n o d e $wslScript - e U N I T Y _ B R I D G E _ P O R T = $BridgePort
@@ -730,8 +630,6 @@ if ($rustVer -notmatch "MISSING") {
Write-Info " 安装 Rust 工具链... "
$installRustCmd = @"
s u d o a p t - g e t i n s t a l l - y - q q b u i l d - e s s e n t i a l p k g - c o n f i g l i b s s l - d e v 2 > / d e v / n u l l | | t r u e
# m i r r o r e d 模 式 下 直 接 用 1 2 7 . 0 . 0 . 1 , r u s t u p 用 e n v 代 理
. ~ / . m c p - p r o x y . e n v 2 > / d e v / n u l l | | t r u e
c u r l - - p r o t o ' = h t t p s ' - - t l s v 1 . 2 - s S f h t t p s : / / s h . r u s t u p . r s - o / t m p / r u s t u p - i n i t . s h
s h / t m p / r u s t u p - i n i t . s h - y - - d e f a u l t - t o o l c h a i n s t a b l e - - n o - m o d i f y - p a t h
s o u r c e ~ / . c a r g o / e n v
@@ -750,15 +648,7 @@ if ($rtkVer -notmatch "MISSING") {
Write-Info " 安装 rtk (Rust Token Killer)... "
$installRtkCmd = @"
. ~ / . c a r g o / e n v 2 > / d e v / n u l l | | t r u e
# m i r r o r e d 模 式 : C A R G O _ N E T _ G I T _ F E T C H _ W I T H _ C L I 让 c a r g o 用 系 统 g i t ( 走 代 理 )
# 但 g i t c l o n e 到 g i t h u b 时 用 直 连 ( g i t p r o x y 不 影 响 h t t p s )
_ s a v e d _ h t t p = ` $( git config - -global http . proxy 2 > / dev / null )
_ s a v e d _ h t t p s = ` $( git config - -global https . proxy 2 > / dev / null )
g i t c o n f i g - - g l o b a l - - u n s e t h t t p . p r o x y 2 > / d e v / n u l l | | t r u e
g i t c o n f i g - - g l o b a l - - u n s e t h t t p s . p r o x y 2 > / d e v / n u l l | | t r u e
C A R G O _ N E T _ G I T _ F E T C H _ W I T H _ C L I = t r u e c a r g o i n s t a l l - - g i t h t t p s : / / g i t h u b . c o m / r t k - a i / r t k 2 > & 1 | t a i l - 5
[ - n " ` $_saved_http " ] & & g i t c o n f i g - - g l o b a l h t t p . p r o x y " ` $_saved_http " | | t r u e
[ - n " ` $_saved_https " ] & & g i t c o n f i g - - g l o b a l h t t p s . p r o x y " ` $_saved_https " | | t r u e
"@
Invoke-WSL $installRtkCmd -IgnoreError
$rtkCheck = Invoke-WSL " . ~/.cargo/env 2>/dev/null; rtk --version 2>/dev/null || echo FAILED " -IgnoreError
@@ -829,11 +719,6 @@ foreach ($it in $items) {
Write-Host ( " {0,-16} {1} " -f $it [ 0 ] , $ ( if ( $it [ 1 ] ) { $it [ 1 ] } else { " (未安装) " } ) ) -ForegroundColor White
}
if ( $resolvedProxyPort -gt 0 ) {
Write-Host " "
Write-Host " v2rayN 代理 127.0.0.1: $resolvedProxyPort (WSL2 通过 Windows 主机 IP 访问) " -ForegroundColor DarkGray
}
Write-Host " "
Write-Host " ━━━━ 后续步骤 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ " -ForegroundColor Cyan
Write-Host " 1) 在 Unity 项目中安装 MCP Plugin( 每个项目一次) : " -ForegroundColor White