fix: discover MCP servers from CLI when not in settings.json - #43
Conversation
Claude Code CLI stores MCP configs in an internal location that CodePilot cannot read from ~/.claude/settings.json. This adds CLI discovery via `claude mcp list` with 60s caching, merges CLI/user/ project MCP sources for both the extensions page and chat sessions, and changes settings PUT to merge instead of overwrite to prevent losing CLI-configured MCP servers. Closes#42 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gy212
commented
Feb 9, 2026
不是哥们,提交完发现又更新了 |
1 similar comment
gy212
commented
Feb 9, 2026
不是哥们,提交完发现又更新了 |
gy212
commented
Feb 9, 2026
基于0.6.4,可能与0.7存在冲突。 |
op7418
left a comment
There was a problem hiding this comment.
Thanks for the PR! The approach of discovering MCP servers from claude mcp list is sound and addresses a real gap. A few issues to address before merging:
Medium:
execFileSyncblocks the event loop —discoverCliMcpServers()usesexecFileSyncwith a 10s timeout, called from the chat API route. The first call (or any after cache expiry) will block ALL concurrent requests. Please switch to asyncexecFile(withutil.promisify) and make the call chain async.Brittle CLI output parsing — The regex
^(\S+):\s+(.+?)\s+-\s+[✓✗]parses human-readable output fromclaude mcp list. This will break if the CLI changes its format, server names contain spaces/colons, or status indicators change. Consider checking ifclaude mcp list --jsonis available, or at minimum document this as a known limitation.
Low:
Shallow merge in PUT handler (
settings/route.ts:52-54) —{ ...existing, ...settings }only works if the frontend omits fields it doesn't manage. If it sendsmcpServers: {}, it will overwrite existing config. Consider a more targeted merge.sourcefield type mismatch — Thesourceproperty added to MCP configs in the GET handler isn't reflected in theMCPConfigResponsetype.No cache invalidation — The 60s TTL is reasonable, but there's no way to force-refresh after adding a new MCP server via CLI. Consider adding a manual refresh mechanism.
Code quality is otherwise good — defensive error handling, proper use of execFileSync (not exec) for security, and sensible merge priority ordering.
- Convert execFileSync to async execFile to avoid blocking the event loop - Add forceRefresh param and invalidateCliMcpCache() for manual cache refresh - Support ?refresh=true query param on MCP GET endpoint - Wrap per-line CLI output parsing in try-catch for robustness - Add comments noting claude mcp list --json is not yet available - Fix settings PUT to skip empty objects, preventing accidental mcpServers wipe - Add source field to MCPServerConfig type definition Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gy212
commented
Feb 10, 2026
已按本轮 review 意见完成修复,补充说明如下: ✅ 1) CLI MCP 服务器改为“只显示,不落盘”
✅ 2) |
`claude mcp list` fails on Windows due to Git Bash detection issues, so CLI discovery returns empty. Add direct file read from ~/.claude.json (where `claude mcp add` stores configs) as a reliable fallback source. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gy212
commented
Feb 11, 2026
已完成本次适配与复核,结论如下:
本地验证: px tsx --test src/tests/unit/mcp-cli-parser.test.ts ✅px tsx --test src/tests/unit/mcp-config.test.ts ✅px eslint(针对本 PR 涉及文件)✅ Review 结论:当前版本无 blocker/high 问题,可继续走合并流程。 |
op7418
left a comment
There was a problem hiding this comment.
Well-designed MCP CLI discovery feature. Multi-source merging logic is clean, 60s cache is sensible, read-only UI for CLI servers is good UX. CLI output parsing is inherently fragile but mitigated by the ~/.claude.json fallback.
Please rebase onto current main before merge.
op7418
commented
Feb 23, 2026
你好 @gy212,感谢你提交这个 MCP 发现的修复! MCP 服务器的读取问题已经在主分支通过以下 commit 修复了:
该 commit 支持从多个配置文件位置读取 MCP 服务器配置,解决了 CLI 配置的 MCP 服务器无法被发现的问题。 因此先关闭这个 PR。再次感谢你的贡献! |
…ed (#632) Signal — Codex 复审 #632 P1+item1 后给三点: - [P2] resolveEffectiveAnthropicBaseUrl 在 provider 存在但 hasCredentials=false 时仍优先返回 provider.base_url,与 toClaudeCodeEnv 不一致(该状态两分支都不跑、SDK 只继承 ambient ANTHROPIC_BASE_URL)。若用户选了无 key 的 DB provider + 环境有第三方 ANTHROPIC_BASE_URL, gate 可能按错地址误信窗口(同 GLM 同类漏口)。 - [P3] 存量第三方会话首屏可能在 provider models 加载前(undefined→trusted)短暂闪历史 200K。 - [P3] tech-debt 新条目用了 #36,与既有 #36 撞车。 Triage — - P2:helper 只镜像了 toClaudeCodeEnv 两态(有凭据 provider / 无 provider),漏第三态(有 provider 无凭据):该态 provider 分支 gated on hasCredentials、env 分支 gated on !provider, 两者都不跑 → env 保持 ambient process.env.ANTHROPIC_BASE_URL,provider.base_url 不注入、 settings 不读。 - P3 闪回:undefined 同时表示"加载中"与"非 anthropic 组未标注",前者应 fail-closed。 - P3 编号:tracker 非严格连续,实际最大 42 → 下一个可用 43。 Fix — - provider-resolver:helper 改三态镜像。`provider && !hasCredentials` → 返回 process.env.ANTHROPIC_BASE_URL(忠实镜像 SDK 继承的 ambient env,不读 provider.base_url / settings)。doc 写明三态对应关系。 - ChatView:fail-closed —— providerFetchState !== 'loaded' 传 false;loaded 时用 group flag (found 必有标注;not-found stale provider → ?? true 向后兼容)。第一方代价 = 首屏短暂只显 已用、百分比后补的渐进式诚实显示,绝不闪错数。 - tech-debt #36 → #43(plan doc / memory 引用同步)。 Verify — npm run test 3387/3387(typecheck clean)。新增 P2 回归 2 例:无凭据 provider 背后 第三方 env → untrust;无凭据 provider + clean env → 不误 untrust。 Guardrail — provider-resolver.test.ts 加 P2 三态行为测试;context-window-trusted.test.ts 的 ChatView pin 更新为锁定 fail-closed 语义(providerFetchState === 'loaded' ? (… ?? true) : false)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ed (op7418#632) Signal — Codex 复审 op7418#632 P1+item1 后给三点: - [P2] resolveEffectiveAnthropicBaseUrl 在 provider 存在但 hasCredentials=false 时仍优先返回 provider.base_url,与 toClaudeCodeEnv 不一致(该状态两分支都不跑、SDK 只继承 ambient ANTHROPIC_BASE_URL)。若用户选了无 key 的 DB provider + 环境有第三方 ANTHROPIC_BASE_URL, gate 可能按错地址误信窗口(同 GLM 同类漏口)。 - [P3] 存量第三方会话首屏可能在 provider models 加载前(undefined→trusted)短暂闪历史 200K。 - [P3] tech-debt 新条目用了 op7418#36,与既有 op7418#36 撞车。 Triage — - P2:helper 只镜像了 toClaudeCodeEnv 两态(有凭据 provider / 无 provider),漏第三态(有 provider 无凭据):该态 provider 分支 gated on hasCredentials、env 分支 gated on !provider, 两者都不跑 → env 保持 ambient process.env.ANTHROPIC_BASE_URL,provider.base_url 不注入、 settings 不读。 - P3 闪回:undefined 同时表示"加载中"与"非 anthropic 组未标注",前者应 fail-closed。 - P3 编号:tracker 非严格连续,实际最大 42 → 下一个可用 43。 Fix — - provider-resolver:helper 改三态镜像。`provider && !hasCredentials` → 返回 process.env.ANTHROPIC_BASE_URL(忠实镜像 SDK 继承的 ambient env,不读 provider.base_url / settings)。doc 写明三态对应关系。 - ChatView:fail-closed —— providerFetchState !== 'loaded' 传 false;loaded 时用 group flag (found 必有标注;not-found stale provider → ?? true 向后兼容)。第一方代价 = 首屏短暂只显 已用、百分比后补的渐进式诚实显示,绝不闪错数。 - tech-debt op7418#36 → op7418#43(plan doc / memory 引用同步)。 Verify — npm run test 3387/3387(typecheck clean)。新增 P2 回归 2 例:无凭据 provider 背后 第三方 env → untrust;无凭据 provider + clean env → 不误 untrust。 Guardrail — provider-resolver.test.ts 加 P2 三态行为测试;context-window-trusted.test.ts 的 ChatView pin 更新为锁定 fail-closed 语义(providerFetchState === 'loaded' ? (… ?? true) : false)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
问题
通过
claude mcp add -s user配置的 MCP 服务器在 CodePilot 中无法被发现和使用。扩展页面显示"未配置 MCP 服务器",聊天中也无法使用 MCP 工具。根本原因:Claude Code CLI 新版本将 MCP 配置存储在内部位置,而非
~/.claude/settings.json的mcpServers字段。CodePilot 只从settings.json读取,因此找不到任何 CLI 配置的服务器。环境:Windows 11
Closes#42
修改内容
1.
src/lib/mcp-config.ts— 新增 CLI 发现能力discoverCliMcpServers():调用claude mcp list解析输出,提取服务器名称和命令findClaudeBinary()和findGitBash()确保跨平台兼容getMergedMcpServers():合并三个来源(CLI < settings.json < .mcp.json)2.
src/app/api/plugins/mcp/route.ts— 扩展页面展示 CLI 服务器source: 'cli' | 'settings'方便前端区分3.
src/app/api/chat/route.ts— 聊天时传递 MCP 配置getMergedMcpServers,将合并后的 MCP 配置传递给streamClaude()4.
src/app/api/settings/route.ts— 防止设置保存覆盖 MCP 配置mcpServers)验证方式