fix: v2.0.3 - MCP 注入改用临时 JS 文件执行 (避免 -e 参数解析)
v2.0.2 的 node -e + -- 参数传递在 PowerShell 下 argv 偏移导致 mcpServers 为空。 改为: 将合并脚本写入 %TEMP%/bw-inject-mcp.js 再 node 执行, 绕过所有参数解析陷阱。 新增 inject-mcp.js 独立脚本供手动执行。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6168279f78
commit
aee3cc708b
@ -16,7 +16,7 @@ param(
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
|
||||
$BWVersion = "2.0.2"
|
||||
$BWVersion = "2.0.3"
|
||||
|
||||
# ─── B4: 单实例保护 (防止双击两次导致竞态) ─────────
|
||||
$mutexCreated = $false
|
||||
@ -1104,35 +1104,36 @@ if (Test-Path $templateFile) {
|
||||
|
||||
# ── ~/.claude.json (Claude Code v2.1+ MCP 服务器配置的正确位置) ──
|
||||
# Claude Code 不再从 settings.json 读取 mcpServers, 必须写入 ~/.claude.json
|
||||
# 用 Node.js 做 JSON 合并 (避免 PowerShell ConvertTo-Json 深度/类型陷阱)
|
||||
# 策略: 将合并脚本写入临时 .js 文件再用 node 执行 (避免 -e 参数解析问题)
|
||||
$claudeJsonFile = Join-Path $env:USERPROFILE ".claude.json"
|
||||
$mcpTmpFile = Join-Path $env:TEMP "bw-mcp-servers.json"
|
||||
$mcpTmpJs = Join-Path $env:TEMP "bw-inject-mcp.js"
|
||||
try {
|
||||
# 从渲染后的 settings.json 提取 mcpServers 写入临时文件
|
||||
# 从渲染后的 settings.json 提取 mcpServers, 生成 Node.js 合并脚本
|
||||
$settingsObj = ConvertFrom-Json $content
|
||||
if ($settingsObj.mcpServers) {
|
||||
# 过滤掉 __comment 键
|
||||
# 构建 mcpServers 的 JSON (过滤 __comment 键)
|
||||
$cleanMcp = @{}
|
||||
foreach ($prop in $settingsObj.mcpServers.PSObject.Properties) {
|
||||
if ($prop.Name -notlike '__*') { $cleanMcp[$prop.Name] = $prop.Value }
|
||||
}
|
||||
[PSCustomObject]$cleanMcp | ConvertTo-Json -Depth 10 | Set-Content $mcpTmpFile -Encoding UTF8
|
||||
$mcpJsonStr = ([PSCustomObject]$cleanMcp | ConvertTo-Json -Depth 10 -Compress)
|
||||
|
||||
# Node.js 安全合并: 保留 .claude.json 所有现有字段, 只注入 mcpServers
|
||||
$mergeJs = @'
|
||||
const fs=require("fs");
|
||||
const target=process.argv[2], src=process.argv[3];
|
||||
let data={};
|
||||
try{data=JSON.parse(fs.readFileSync(target,"utf8"))}catch(e){}
|
||||
const mcp=JSON.parse(fs.readFileSync(src,"utf8"));
|
||||
data.mcpServers=mcp;
|
||||
fs.writeFileSync(target,JSON.stringify(data,null,2),"utf8");
|
||||
const n=Object.keys(mcp).length;
|
||||
console.log(n);
|
||||
'@
|
||||
$nodeOut = & node -e $mergeJs -- $claudeJsonFile $mcpTmpFile 2>&1
|
||||
# 生成独立 JS 脚本文件 (不依赖 -e 参数传递, 不受终端换行影响)
|
||||
$jsLines = @(
|
||||
'var fs=require("fs");'
|
||||
"var p=`"$($claudeJsonFile.Replace('\','/'))`";"
|
||||
'var d={};'
|
||||
'try{d=JSON.parse(fs.readFileSync(p,"utf8"))}catch(e){}'
|
||||
"var mcp=$mcpJsonStr;"
|
||||
'd.mcpServers=mcp;'
|
||||
'fs.writeFileSync(p,JSON.stringify(d,null,2));'
|
||||
'console.log(Object.keys(mcp).length);'
|
||||
)
|
||||
$jsLines -join "`n" | Set-Content $mcpTmpJs -Encoding UTF8
|
||||
|
||||
$nodeOut = & node $mcpTmpJs 2>&1
|
||||
$mcpCount = ($nodeOut | Select-Object -First 1).ToString().Trim()
|
||||
Remove-Item $mcpTmpFile -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item $mcpTmpJs -Force -ErrorAction SilentlyContinue
|
||||
Log-OK ".claude.json 已写入 ($mcpCount 个 MCP 服务器)"
|
||||
}
|
||||
} catch {
|
||||
|
||||
136
inject-mcp.js
Normal file
136
inject-mcp.js
Normal file
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Bookworm MCP 注入脚本
|
||||
* 将 MCP 服务器配置写入 ~/.claude.json (Claude Code v2.1+ 正确位置)
|
||||
* 用法: node inject-mcp.js
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const f = path.join(process.env.USERPROFILE, ".claude.json");
|
||||
let d = {};
|
||||
try {
|
||||
d = JSON.parse(fs.readFileSync(f, "utf8"));
|
||||
} catch (e) {
|
||||
console.log("未找到 .claude.json, 将创建新文件");
|
||||
}
|
||||
|
||||
d.mcpServers = {
|
||||
"context7": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "@upstash/context7-mcp@2.1.1"],
|
||||
type: "stdio"
|
||||
},
|
||||
"sequential-thinking": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "@modelcontextprotocol/server-sequential-thinking@2025.12.18"],
|
||||
type: "stdio"
|
||||
},
|
||||
"playwright": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "@playwright/mcp@0.0.68", "--headless"],
|
||||
type: "stdio"
|
||||
},
|
||||
"session-continuity": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "claude-session-continuity-mcp@1.13.0"],
|
||||
type: "stdio"
|
||||
},
|
||||
"notebooklm": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "notebooklm-mcp@latest"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
https_proxy: "http://127.0.0.1:7893",
|
||||
http_proxy: "http://127.0.0.1:7893"
|
||||
}
|
||||
},
|
||||
"cloudflare": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "mcp-remote", "https://docs.mcp.cloudflare.com/sse"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
https_proxy: "http://127.0.0.1:7893",
|
||||
http_proxy: "http://127.0.0.1:7893"
|
||||
}
|
||||
},
|
||||
"chrome-devtools": {
|
||||
command: "npx.cmd",
|
||||
args: [
|
||||
"--yes", "chrome-devtools-mcp@0.18.1",
|
||||
"--executablePath", "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
||||
"--viewport", "1280x720",
|
||||
"--proxyServer", "http://127.0.0.1:7893"
|
||||
],
|
||||
type: "stdio"
|
||||
},
|
||||
"github": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "@modelcontextprotocol/server-github"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN: process.env.GITHUB_PERSONAL_ACCESS_TOKEN || ""
|
||||
}
|
||||
},
|
||||
"slack": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "@modelcontextprotocol/server-slack"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
SLACK_BOT_TOKEN: process.env.SLACK_BOT_TOKEN || "",
|
||||
SLACK_TEAM_ID: "T0A4L1JLEER"
|
||||
}
|
||||
},
|
||||
"firecrawl": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "firecrawl-mcp"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
FIRECRAWL_API_KEY: process.env.FIRECRAWL_API_KEY || ""
|
||||
}
|
||||
},
|
||||
"browserbase": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "@anthropic-ai/browserbase-mcp"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
BROWSERBASE_API_KEY: process.env.BROWSERBASE_API_KEY || "",
|
||||
BROWSERBASE_PROJECT_ID: "d3dbb32f-be2f-4e3a-b9ec-68e27474763c"
|
||||
}
|
||||
},
|
||||
"mcp-image": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "mcp-image"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
GEMINI_API_KEY: process.env.GEMINI_API_KEY || ""
|
||||
}
|
||||
},
|
||||
"google-drive": {
|
||||
command: "npx.cmd",
|
||||
args: ["--yes", "@piotr-agier/google-drive-mcp"],
|
||||
type: "stdio"
|
||||
},
|
||||
"windows-mcp": {
|
||||
command: "uvx",
|
||||
args: ["--python", "3.13", "windows-mcp"],
|
||||
type: "stdio"
|
||||
},
|
||||
"atlassian": {
|
||||
command: "uvx",
|
||||
args: ["mcp-atlassian"],
|
||||
type: "stdio",
|
||||
env: {
|
||||
JIRA_URL: "https://huakoh.atlassian.net",
|
||||
JIRA_USERNAME: "huakoh449@gmail.com",
|
||||
JIRA_API_TOKEN: process.env.ATLASSIAN_API_TOKEN || "",
|
||||
CONFLUENCE_URL: "https://huakoh.atlassian.net/wiki",
|
||||
CONFLUENCE_USERNAME: "huakoh449@gmail.com",
|
||||
CONFLUENCE_API_TOKEN: process.env.ATLASSIAN_API_TOKEN || ""
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fs.writeFileSync(f, JSON.stringify(d, null, 2));
|
||||
const count = Object.keys(d.mcpServers).length;
|
||||
console.log("OK: " + count + " MCP servers written to " + f);
|
||||
console.log("请重启 Claude Code 后运行 /mcp 验证");
|
||||
Loading…
Reference in New Issue
Block a user