fix(cc-config): MCP scope was inverted — expose user/local, not user/project

readMcpServers only ever parses ~/.claude.json (top-level = user scope,
projects[<root>] = the panel's "projectScoped" bucket, which the CLI itself
calls `local`). The previous user/project scope choice was the exact
inverse: `--scope project` writes .mcp.json, which readMcpServers never
reads (a successful add would vanish), and every "projectScoped" row was
actually `local`, so Remove sent a scope the CLI could never match.

- cc-mcp-cli.js: MCP_SCOPES -> ["user", "local"]; drop the local
  mutationQueue/serialize in favor of cc-plugin-cli.js's exported one, so a
  plugin install and an MCP add can't spawn `claude` concurrently; drop the
  String(v) coercion in env/header flags (a wrong-typed value is now a 400,
  not a written "[object Object]"); assertEmbeddedValue allows empty strings
  (a legitimate empty stdio arg was previously a 400).
- cc-plugin-cli.js: export `serialize` for reuse.
- CcConfig.tsx: CcMcpScope narrowed to user/local; the projectScoped bucket's
  McpCard now sends scope="local"; rows sourced from
  ~/.claude/settings.json (no CLI scope addresses them) no longer render a
  Remove button. Cleaned up i18n keys my own earlier change made dead
  (explain.mcp.addCmd/remove/removeButton) and gave the scope <select> its
  own short option labels instead of reusing full-sentence section headings.
This commit is contained in:
2026-09-09 09:36:52 +07:00
parent fd4edaac98
commit 6d27c115d8
11 changed files with 159 additions and 59 deletions
+7 -4
View File
@@ -2671,10 +2671,13 @@ export interface CcMcpResponse {
projectScoped: CcMcpServer[];
}
/** Scope the `claude mcp` CLI accepts from this form. Deliberately not the
* three-value settings union — the CLI's own third scope (`local`) is a
* different axis and is not offered here. */
export type CcMcpScope = "user" | "project";
/** Scope the `claude mcp` CLI accepts from this form — `user` and `local`
* ONLY, matching what GET /mcp's `readMcpServers` can actually see:
* `user` is `~/.claude.json` top-level, `local` is its `projects[<root>]`
* block (the panel's `projectScoped` bucket, despite the name). The CLI's
* `project` scope writes `.mcp.json`, which `readMcpServers` never reads —
* offering it here would add a server the dashboard can never show exists. */
export type CcMcpScope = "user" | "local";
/** Body of POST /api/cc-config/mcp/add. Either `url` (http/sse) or
* `command`+`args` (stdio) is required, never both. `env` is stdio-only;