feat: v2.1.0 - 同步 22 MCP + 简化 Phase 5 注入逻辑
Phase 5 MCP 注入改为直接调用 ~/.claude/inject-mcp.js (从 config 仓库), 移除复杂的 PowerShell JSON 提取+临时脚本生成逻辑。 inject-mcp.js 包含完整 22 个 portable MCP server 配置。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
aee3cc708b
commit
15449c86d8
@ -16,7 +16,7 @@ param(
|
|||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
|
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
|
||||||
$BWVersion = "2.0.3"
|
$BWVersion = "2.1.0"
|
||||||
|
|
||||||
# ─── B4: 单实例保护 (防止双击两次导致竞态) ─────────
|
# ─── B4: 单实例保护 (防止双击两次导致竞态) ─────────
|
||||||
$mutexCreated = $false
|
$mutexCreated = $false
|
||||||
@ -1103,38 +1103,15 @@ if (Test-Path $templateFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ── ~/.claude.json (Claude Code v2.1+ MCP 服务器配置的正确位置) ──
|
# ── ~/.claude.json (Claude Code v2.1+ MCP 服务器配置的正确位置) ──
|
||||||
# Claude Code 不再从 settings.json 读取 mcpServers, 必须写入 ~/.claude.json
|
# 直接调用 config 仓库里的 inject-mcp.js (包含全部 22 个 portable MCP)
|
||||||
# 策略: 将合并脚本写入临时 .js 文件再用 node 执行 (避免 -e 参数解析问题)
|
$injectScript = Join-Path $ClaudeDir "inject-mcp.js"
|
||||||
$claudeJsonFile = Join-Path $env:USERPROFILE ".claude.json"
|
|
||||||
$mcpTmpJs = Join-Path $env:TEMP "bw-inject-mcp.js"
|
|
||||||
try {
|
try {
|
||||||
# 从渲染后的 settings.json 提取 mcpServers, 生成 Node.js 合并脚本
|
if (Test-Path $injectScript) {
|
||||||
$settingsObj = ConvertFrom-Json $content
|
$nodeOut = & node $injectScript 2>&1
|
||||||
if ($settingsObj.mcpServers) {
|
$firstLine = ($nodeOut | Select-Object -First 1).ToString().Trim()
|
||||||
# 构建 mcpServers 的 JSON (过滤 __comment 键)
|
Log-OK $firstLine
|
||||||
$cleanMcp = @{}
|
} else {
|
||||||
foreach ($prop in $settingsObj.mcpServers.PSObject.Properties) {
|
Bw-Log "WARN" "inject-mcp.js 不存在, 跳过 MCP 注入"
|
||||||
if ($prop.Name -notlike '__*') { $cleanMcp[$prop.Name] = $prop.Value }
|
|
||||||
}
|
|
||||||
$mcpJsonStr = ([PSCustomObject]$cleanMcp | ConvertTo-Json -Depth 10 -Compress)
|
|
||||||
|
|
||||||
# 生成独立 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 $mcpTmpJs -Force -ErrorAction SilentlyContinue
|
|
||||||
Log-OK ".claude.json 已写入 ($mcpCount 个 MCP 服务器)"
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Bw-Log "WARN" ".claude.json 生成失败: $_"
|
Bw-Log "WARN" ".claude.json 生成失败: $_"
|
||||||
|
|||||||
152
inject-mcp.js
152
inject-mcp.js
@ -1,136 +1,104 @@
|
|||||||
/**
|
/**
|
||||||
* Bookworm MCP 注入脚本
|
* Bookworm MCP 注入脚本 v2 — 同步 Bookworm v6.5.1 全部 22 个 portable MCP
|
||||||
* 将 MCP 服务器配置写入 ~/.claude.json (Claude Code v2.1+ 正确位置)
|
* 安全合并到 ~/.claude.json (保留所有现有字段)
|
||||||
* 用法: node inject-mcp.js
|
* 用法: node inject-mcp.js
|
||||||
*/
|
*/
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const HOME = process.env.USERPROFILE || process.env.HOME || "";
|
||||||
|
|
||||||
const f = path.join(process.env.USERPROFILE, ".claude.json");
|
const f = path.join(HOME, ".claude.json");
|
||||||
let d = {};
|
let d = {};
|
||||||
try {
|
try { d = JSON.parse(fs.readFileSync(f, "utf8")); } catch (e) {}
|
||||||
d = JSON.parse(fs.readFileSync(f, "utf8"));
|
|
||||||
} catch (e) {
|
|
||||||
console.log("未找到 .claude.json, 将创建新文件");
|
|
||||||
}
|
|
||||||
|
|
||||||
d.mcpServers = {
|
d.mcpServers = {
|
||||||
|
// ── Tier 1: npx (无需 API Key) ──
|
||||||
"context7": {
|
"context7": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@upstash/context7-mcp@2.1.1"], type: "stdio"
|
||||||
args: ["--yes", "@upstash/context7-mcp@2.1.1"],
|
|
||||||
type: "stdio"
|
|
||||||
},
|
},
|
||||||
"sequential-thinking": {
|
"sequential-thinking": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@modelcontextprotocol/server-sequential-thinking@2025.12.18"], type: "stdio"
|
||||||
args: ["--yes", "@modelcontextprotocol/server-sequential-thinking@2025.12.18"],
|
|
||||||
type: "stdio"
|
|
||||||
},
|
},
|
||||||
"playwright": {
|
"playwright": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@playwright/mcp@0.0.68", "--headless"], type: "stdio"
|
||||||
args: ["--yes", "@playwright/mcp@0.0.68", "--headless"],
|
|
||||||
type: "stdio"
|
|
||||||
},
|
},
|
||||||
"session-continuity": {
|
"session-continuity": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "claude-session-continuity-mcp@1.13.0"], type: "stdio"
|
||||||
args: ["--yes", "claude-session-continuity-mcp@1.13.0"],
|
|
||||||
type: "stdio"
|
|
||||||
},
|
},
|
||||||
"notebooklm": {
|
"browser-mcp": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@browsermcp/mcp@latest"], type: "stdio"
|
||||||
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": {
|
"desktop-commander": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@wonderwhy-er/desktop-commander@latest"], type: "stdio",
|
||||||
args: ["--yes", "mcp-remote", "https://docs.mcp.cloudflare.com/sse"],
|
env: { PUPPETEER_SKIP_DOWNLOAD: "true", PUPPETEER_EXECUTABLE_PATH: "C:/Program Files/Google/Chrome/Application/chrome.exe" }
|
||||||
type: "stdio",
|
|
||||||
env: {
|
|
||||||
https_proxy: "http://127.0.0.1:7893",
|
|
||||||
http_proxy: "http://127.0.0.1:7893"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"chrome-devtools": {
|
"chrome-devtools": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd",
|
||||||
args: [
|
args: ["--yes", "chrome-devtools-mcp@0.18.1",
|
||||||
"--yes", "chrome-devtools-mcp@0.18.1",
|
|
||||||
"--executablePath", "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
"--executablePath", "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
||||||
"--viewport", "1280x720",
|
"--viewport", "1280x720", "--proxyServer", "http://127.0.0.1:7893"],
|
||||||
"--proxyServer", "http://127.0.0.1:7893"
|
|
||||||
],
|
|
||||||
type: "stdio"
|
type: "stdio"
|
||||||
},
|
},
|
||||||
|
"mobile": {
|
||||||
|
command: "npx.cmd", args: ["--yes", "@mobilenext/mobile-mcp@0.0.35"], type: "stdio",
|
||||||
|
env: { ANDROID_HOME: path.join(HOME, "android-sdk") }
|
||||||
|
},
|
||||||
|
|
||||||
|
// ── Tier 2: npx + API Key (凭证从环境变量读取) ──
|
||||||
"github": {
|
"github": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@modelcontextprotocol/server-github"], type: "stdio",
|
||||||
args: ["--yes", "@modelcontextprotocol/server-github"],
|
env: { GITHUB_PERSONAL_ACCESS_TOKEN: process.env.GITHUB_PERSONAL_ACCESS_TOKEN || "" }
|
||||||
type: "stdio",
|
|
||||||
env: {
|
|
||||||
GITHUB_PERSONAL_ACCESS_TOKEN: process.env.GITHUB_PERSONAL_ACCESS_TOKEN || ""
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"slack": {
|
"slack": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@modelcontextprotocol/server-slack"], type: "stdio",
|
||||||
args: ["--yes", "@modelcontextprotocol/server-slack"],
|
env: { SLACK_BOT_TOKEN: process.env.SLACK_BOT_TOKEN || "", SLACK_TEAM_ID: "T0A4L1JLEER" }
|
||||||
type: "stdio",
|
|
||||||
env: {
|
|
||||||
SLACK_BOT_TOKEN: process.env.SLACK_BOT_TOKEN || "",
|
|
||||||
SLACK_TEAM_ID: "T0A4L1JLEER"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"firecrawl": {
|
"firecrawl": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "firecrawl-mcp"], type: "stdio",
|
||||||
args: ["--yes", "firecrawl-mcp"],
|
env: { FIRECRAWL_API_KEY: process.env.FIRECRAWL_API_KEY || "" }
|
||||||
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": {
|
"mcp-image": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "mcp-image"], type: "stdio",
|
||||||
args: ["--yes", "mcp-image"],
|
env: { GEMINI_API_KEY: process.env.GEMINI_API_KEY || "", IMAGE_OUTPUT_DIR: path.join(HOME, "Pictures/mcp-images") }
|
||||||
type: "stdio",
|
|
||||||
env: {
|
|
||||||
GEMINI_API_KEY: process.env.GEMINI_API_KEY || ""
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"google-drive": {
|
"google-drive": {
|
||||||
command: "npx.cmd",
|
command: "npx.cmd", args: ["--yes", "@piotr-agier/google-drive-mcp"], type: "stdio",
|
||||||
args: ["--yes", "@piotr-agier/google-drive-mcp"],
|
env: { GOOGLE_DRIVE_OAUTH_CREDENTIALS: path.join(HOME, ".config/google-drive-mcp/gcp-oauth.keys.json") }
|
||||||
type: "stdio"
|
|
||||||
},
|
},
|
||||||
"windows-mcp": {
|
"browserbase": {
|
||||||
command: "uvx",
|
command: "npx.cmd", args: ["--yes", "@anthropic-ai/browserbase-mcp"], type: "stdio",
|
||||||
args: ["--python", "3.13", "windows-mcp"],
|
env: { BROWSERBASE_API_KEY: process.env.BROWSERBASE_API_KEY || "", BROWSERBASE_PROJECT_ID: "d3dbb32f-be2f-4e3a-b9ec-68e27474763c" }
|
||||||
type: "stdio"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ── Tier 3: npx + 代理 (需要外网访问) ──
|
||||||
|
"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" }
|
||||||
|
},
|
||||||
|
|
||||||
|
// ── Tier 4: HTTP (零安装, 云端托管) ──
|
||||||
|
"linear": { type: "http", url: "https://mcp.linear.app/mcp" },
|
||||||
|
"supabase": { type: "http", url: "https://mcp.supabase.com/mcp?project_ref=oepmihbtoylosbsxlmfo" },
|
||||||
|
"figma": { type: "http", url: "https://mcp.figma.com/mcp" },
|
||||||
|
|
||||||
|
// ── Tier 5: Python/uvx (需要 Python + uv) ──
|
||||||
|
"windows-mcp": { command: "uvx", args: ["--python", "3.13", "windows-mcp"], type: "stdio" },
|
||||||
"atlassian": {
|
"atlassian": {
|
||||||
command: "uvx",
|
command: "uvx", args: ["mcp-atlassian"], type: "stdio",
|
||||||
args: ["mcp-atlassian"],
|
|
||||||
type: "stdio",
|
|
||||||
env: {
|
env: {
|
||||||
JIRA_URL: "https://huakoh.atlassian.net",
|
JIRA_URL: "https://huakoh.atlassian.net", JIRA_USERNAME: "huakoh449@gmail.com",
|
||||||
JIRA_USERNAME: "huakoh449@gmail.com",
|
|
||||||
JIRA_API_TOKEN: process.env.ATLASSIAN_API_TOKEN || "",
|
JIRA_API_TOKEN: process.env.ATLASSIAN_API_TOKEN || "",
|
||||||
CONFLUENCE_URL: "https://huakoh.atlassian.net/wiki",
|
CONFLUENCE_URL: "https://huakoh.atlassian.net/wiki", CONFLUENCE_USERNAME: "huakoh449@gmail.com",
|
||||||
CONFLUENCE_USERNAME: "huakoh449@gmail.com",
|
|
||||||
CONFLUENCE_API_TOKEN: process.env.ATLASSIAN_API_TOKEN || ""
|
CONFLUENCE_API_TOKEN: process.env.ATLASSIAN_API_TOKEN || ""
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"computer-control-mcp": { command: "uvx", args: ["computer-control-mcp@latest"], type: "stdio" }
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.writeFileSync(f, JSON.stringify(d, null, 2));
|
fs.writeFileSync(f, JSON.stringify(d, null, 2));
|
||||||
const count = Object.keys(d.mcpServers).length;
|
const count = Object.keys(d.mcpServers).length;
|
||||||
console.log("OK: " + count + " MCP servers written to " + f);
|
console.log("OK: " + count + " MCP servers -> " + f);
|
||||||
console.log("请重启 Claude Code 后运行 /mcp 验证");
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user