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
+4 -4
View File
@@ -8016,7 +8016,7 @@ paths:
tags:
- CcConfig
summary: Add an MCP server
description: 'Mutating. Runs `claude mcp add` — never a direct edit of ~/.claude.json, which the running CLI rewrites concurrently. Body carries either `url` (+ optional `transport: http|sse` and `headers`) for a remote server, or `command` + `args` (+ optional `env`) for a stdio server; exactly one of the two forms is required. `scope` is required and is `user`|`project` only — not the settings union''s third `project-local` value, which is a different axis. A non-zero CLI exit is returned as 422, not 500. Emits a `cc_config_changed` websocket event on success.'
description: 'Mutating. Runs `claude mcp add` — never a direct edit of ~/.claude.json, which the running CLI rewrites concurrently. Body carries either `url` (+ optional `transport: http|sse` and `headers`) for a remote server, or `command` + `args` (+ optional `env`) for a stdio server; exactly one of the two forms is required. `scope` is required and is `user`|`local` only: `user` writes ~/.claude.json''s top level, `local` writes its `projects[<root>]` block (GET /mcp''s `projectScoped` bucket). The CLI''s own `project` scope (a shared `.mcp.json`) is deliberately not offered — `readMcpServers` never reads that file, so a server added there would report success and never appear in the list. A non-zero CLI exit is returned as 422, not 500. Emits a `cc_config_changed` websocket event on success.'
operationId: ccConfigPostMcpAdd
requestBody:
required: true
@@ -8035,7 +8035,7 @@ paths:
type: string
enum:
- user
- project
- local
example: user
transport:
type: string
@@ -8083,7 +8083,7 @@ paths:
tags:
- CcConfig
summary: Remove an MCP server
description: Mutating. Runs `claude mcp remove`. `scope` (`user`|`project`) narrows which config layer to remove from; omit it to let the CLI find the server wherever it exists. A non-zero CLI exit (e.g. the name does not exist) is returned as 422. Emits a `cc_config_changed` websocket event on success.
description: Mutating. Runs `claude mcp remove`. `scope` (`user`|`local`) narrows which config layer to remove from; omit it to let the CLI find the server wherever it exists. The CLI's own `project` scope is refused with 400 — the panel has no row sourced from `.mcp.json` to remove. A non-zero CLI exit (e.g. the name does not exist) is returned as 422. Emits a `cc_config_changed` websocket event on success.
operationId: ccConfigPostMcpRemove
requestBody:
required: true
@@ -8101,7 +8101,7 @@ paths:
type: string
enum:
- user
- project
- local
responses:
'200':
description: The CLI's stdout/stderr on success.