From aee3cc708bed93cfce5f97f133754d11b89584bf Mon Sep 17 00:00:00 2001 From: bookworm Date: Fri, 10 Apr 2026 21:15:53 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20v2.0.3=20-=20MCP=20=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E4=B8=B4=E6=97=B6=20JS=20=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=20(=E9=81=BF=E5=85=8D=20-e=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=A7=A3=E6=9E=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- auto-setup.ps1 | 41 +++++++-------- inject-mcp.js | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 20 deletions(-) create mode 100644 inject-mcp.js diff --git a/auto-setup.ps1 b/auto-setup.ps1 index bf0a926..da76e60 100644 --- a/auto-setup.ps1 +++ b/auto-setup.ps1 @@ -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 { diff --git a/inject-mcp.js b/inject-mcp.js new file mode 100644 index 0000000..b9e669b --- /dev/null +++ b/inject-mcp.js @@ -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 验证");