feat(cc-config): add and remove MCP servers through the claude CLI
Mutation goes through `claude mcp add|remove`, never a direct edit of ~/.claude.json — the running CLI rewrites that file concurrently, so a dashboard write would race it. Reads stay on readMcpServers. The plan specified a --url flag; the real CLI (v2.1.266) has none — commandOrUrl is positional, and --header must trail it or the variadic flag swallows the url. Built against the verified shape.
This commit is contained in:
@@ -387,6 +387,18 @@ const schemas = {
|
||||
},
|
||||
},
|
||||
|
||||
/** Response of a successful mutating `claude mcp …` run. A non-zero CLI
|
||||
* exit arrives as an HTTP 422 error instead of one of these. */
|
||||
CcConfigCliResult: {
|
||||
type: "object",
|
||||
required: ["ok", "stdout", "stderr"],
|
||||
properties: {
|
||||
ok: { type: "boolean", enum: [true] },
|
||||
stdout: { type: "string" },
|
||||
stderr: { type: "string" },
|
||||
},
|
||||
},
|
||||
|
||||
// ── Hooks ────────────────────────────────────────────────────────────
|
||||
CcConfigHookEntry: {
|
||||
type: "object",
|
||||
@@ -1580,6 +1592,98 @@ const paths = {
|
||||
},
|
||||
},
|
||||
|
||||
"/api/cc-config/mcp/add": {
|
||||
post: {
|
||||
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.",
|
||||
operationId: "ccConfigPostMcpAdd",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
required: ["name", "scope"],
|
||||
properties: {
|
||||
name: { type: "string", example: "vercel" },
|
||||
scope: { type: "string", enum: ["user", "project"], example: "user" },
|
||||
transport: { type: "string", enum: ["http", "sse"] },
|
||||
url: { type: "string", example: "https://mcp.vercel.com" },
|
||||
headers: {
|
||||
type: "object",
|
||||
additionalProperties: { type: "string" },
|
||||
example: { Authorization: "Bearer xyz" },
|
||||
},
|
||||
command: { type: "string", example: "npx" },
|
||||
args: {
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
example: ["-y", "server-github"],
|
||||
},
|
||||
env: {
|
||||
type: "object",
|
||||
additionalProperties: { type: "string" },
|
||||
example: { GITHUB_TOKEN: "xxx" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "The CLI's stdout/stderr on success.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/CcConfigCliResult" },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: { description: "Bad name/scope/args, or an incompatible combination." },
|
||||
422: { description: "The CLI exited non-zero (e.g. the name is already taken)." },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"/api/cc-config/mcp/remove": {
|
||||
post: {
|
||||
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.",
|
||||
operationId: "ccConfigPostMcpRemove",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
required: ["name"],
|
||||
properties: {
|
||||
name: { type: "string", example: "vercel" },
|
||||
scope: { type: "string", enum: ["user", "project"] },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "The CLI's stdout/stderr on success.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/components/schemas/CcConfigCliResult" },
|
||||
},
|
||||
},
|
||||
},
|
||||
400: { description: "Bad name/scope." },
|
||||
422: { description: "The CLI exited non-zero (e.g. no such server)." },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"/api/cc-config/hooks": {
|
||||
get: {
|
||||
tags: ["CcConfig"],
|
||||
|
||||
Reference in New Issue
Block a user