add-mcp 1.10.4 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -21
- package/dist/{chunk-ONLHW5AV.js → chunk-IPCKQUBH.js} +232 -17
- package/dist/index.js +118 -6
- package/dist/lib.d.ts +59 -3
- package/dist/lib.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ MCP servers can be installed to any of these agents:
|
|
|
50
50
|
|
|
51
51
|
| Agent | `--agent` | Project Path | Global Path |
|
|
52
52
|
| ---------------------- | -------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
53
|
-
| Antigravity | `antigravity` | - | `~/.gemini/
|
|
53
|
+
| Antigravity | `antigravity` | - | `~/.gemini/config/mcp_config.json` (shared by Antigravity, Antigravity IDE, and Antigravity CLI) |
|
|
54
54
|
| Cline VSCode Extension | `cline` | - | `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` |
|
|
55
55
|
| Cline CLI | `cline-cli` | - | `~/.cline/data/settings/cline_mcp_settings.json` |
|
|
56
56
|
| Claude Code | `claude-code` | `.mcp.json` | `~/.claude.json` |
|
|
@@ -124,6 +124,16 @@ npx add-mcp https://mcp.example.com/sse --transport sse
|
|
|
124
124
|
# Remote MCP server with auth header
|
|
125
125
|
npx add-mcp https://mcp.example.com/mcp --header "Authorization: Bearer $TOKEN"
|
|
126
126
|
|
|
127
|
+
# Remote server with a request timeout and OAuth scopes
|
|
128
|
+
# (each agent only keeps the fields it supports; others are dropped with a warning)
|
|
129
|
+
npx add-mcp https://mcp.example.com/mcp --timeout 30000 --scopes "read,write"
|
|
130
|
+
|
|
131
|
+
# Auto-approve all tools for agents that support it (Codex, Claude Code)
|
|
132
|
+
npx add-mcp "executor mcp" --name executor -a codex -a claude-code --auto-approve
|
|
133
|
+
|
|
134
|
+
# Auto-approve only selected tools
|
|
135
|
+
npx add-mcp "executor mcp" --name executor -a codex --auto-approve --approve-tool execute
|
|
136
|
+
|
|
127
137
|
# npm package (runs via npx)
|
|
128
138
|
npx add-mcp @modelcontextprotocol/server-postgres
|
|
129
139
|
|
|
@@ -160,18 +170,60 @@ npx add-mcp https://mcp.example.com/mcp -a cursor -y --gitignore
|
|
|
160
170
|
|
|
161
171
|
### Options
|
|
162
172
|
|
|
163
|
-
| Option
|
|
164
|
-
|
|
|
165
|
-
| `-g, --global`
|
|
166
|
-
| `-a, --agent <agent>`
|
|
167
|
-
| `-t, --transport <type>`
|
|
168
|
-
| `--type <type>`
|
|
169
|
-
| `-h, --header <header>`
|
|
170
|
-
| `--env <env>`
|
|
171
|
-
|
|
|
172
|
-
|
|
|
173
|
-
| `--
|
|
174
|
-
| `--
|
|
173
|
+
| Option | Description |
|
|
174
|
+
| ------------------------- | ------------------------------------------------------------------------ |
|
|
175
|
+
| `-g, --global` | Install to user directory instead of project |
|
|
176
|
+
| `-a, --agent <agent>` | Target specific agents (e.g., `cursor`, `claude-code`). Can be repeated. |
|
|
177
|
+
| `-t, --transport <type>` | Transport type for remote servers: `http` (default), `sse` |
|
|
178
|
+
| `--type <type>` | Alias for `--transport` |
|
|
179
|
+
| `-h, --header <header>` | HTTP header for remote servers (repeatable, `Key: Value`) |
|
|
180
|
+
| `--env <env>` | Env var for local stdio servers (repeatable, `KEY=VALUE`) |
|
|
181
|
+
| `--timeout <ms>` | Request timeout (ms) for remote servers (capability-gated, see below) |
|
|
182
|
+
| `--scopes <scopes>` | OAuth scopes for remote servers, comma-separated (capability-gated) |
|
|
183
|
+
| `--oauth-scopes <scopes>` | Alias for `--scopes` |
|
|
184
|
+
| `--auto-approve` | Auto-approve MCP tool calls for supported agents (Codex, Claude Code) |
|
|
185
|
+
| `--approve-tool <tool>` | Tool to auto-approve with `--auto-approve` (repeatable; defaults to all) |
|
|
186
|
+
| `-n, --name <name>` | Server name (auto-inferred if not provided) |
|
|
187
|
+
| `-y, --yes` | Skip all confirmation prompts |
|
|
188
|
+
| `--all` | Install to all agents |
|
|
189
|
+
| `--gitignore` | Add generated config files to `.gitignore` |
|
|
190
|
+
|
|
191
|
+
#### Capability-gated fields (`--timeout`, `--scopes`)
|
|
192
|
+
|
|
193
|
+
Not every MCP client understands every field. `add-mcp` keeps one canonical
|
|
194
|
+
server config and each agent declares which optional fields it supports, mapping
|
|
195
|
+
them into that client's native shape:
|
|
196
|
+
|
|
197
|
+
| Field | Flag | Supported by | Mapped to |
|
|
198
|
+
| ------------------ | ----------------------------------- | ----------------------- | -------------------------------------------------------- |
|
|
199
|
+
| Timeout | `--timeout` | Claude Code, Gemini CLI | `timeout` (milliseconds) |
|
|
200
|
+
| OAuth scopes | `--scopes` | Cursor, Gemini CLI | Cursor `auth.scopes`, Gemini `oauth.scopes` |
|
|
201
|
+
| Tool auto-approval | `--auto-approve` / `--approve-tool` | Codex, Claude Code | Codex approval modes; Claude Code permission allow rules |
|
|
202
|
+
|
|
203
|
+
When you target an agent that does not support a field, `add-mcp` drops it from
|
|
204
|
+
that agent's config and prints a warning (e.g. _"request timeout is not
|
|
205
|
+
supported by VS Code; dropped from that config."_). Other agents still receive
|
|
206
|
+
it. `--timeout` and `--scopes` apply to remote servers only; `--auto-approve`
|
|
207
|
+
applies to both remote and local servers.
|
|
208
|
+
|
|
209
|
+
#### Auto-approving tool calls (`--auto-approve`)
|
|
210
|
+
|
|
211
|
+
`--auto-approve` preconfigures agent-level approval so the agent doesn't prompt
|
|
212
|
+
before each MCP tool call — useful for servers that already gate actions
|
|
213
|
+
internally. Use `--approve-tool <name>` (repeatable) to approve only specific
|
|
214
|
+
tools; without it, all tools are approved.
|
|
215
|
+
|
|
216
|
+
- **Codex** — writes approval modes into `config.toml`: per-tool
|
|
217
|
+
`tools.<name>.approval_mode = "approve"`, or `default_tools_approval_mode = "approve"` for all tools.
|
|
218
|
+
- **Claude Code** — writes permission allow rules to a separate settings file
|
|
219
|
+
(`.claude/settings.local.json` for project installs, `~/.claude/settings.json`
|
|
220
|
+
for global), e.g. `mcp__<server>__<tool>`, or `mcp__<server>` for all tools.
|
|
221
|
+
The MCP server entry itself stays clean.
|
|
222
|
+
|
|
223
|
+
> Note: Claude Code's all-tools rule (`mcp__<server>`) follows the documented
|
|
224
|
+
> format, but a known Claude Code bug ([#34739](https://github.com/anthropics/claude-code/issues/34739))
|
|
225
|
+
> can still prompt for non-fully-qualified MCP rules. Listing tools explicitly
|
|
226
|
+
> with `--approve-tool` is the most reliable path there.
|
|
175
227
|
|
|
176
228
|
### Transport Types
|
|
177
229
|
|
|
@@ -209,14 +261,16 @@ npx add-mcp find github --all --gitignore
|
|
|
209
261
|
|
|
210
262
|
### Options
|
|
211
263
|
|
|
212
|
-
| Option
|
|
213
|
-
|
|
|
214
|
-
| `-g, --global`
|
|
215
|
-
| `-a, --agent <agent>`
|
|
216
|
-
| `-n, --name <name>`
|
|
217
|
-
| `-y, --yes`
|
|
218
|
-
| `--
|
|
219
|
-
| `--
|
|
264
|
+
| Option | Description |
|
|
265
|
+
| ----------------------- | ------------------------------------------------------------------------ |
|
|
266
|
+
| `-g, --global` | Install to user directory instead of project |
|
|
267
|
+
| `-a, --agent <agent>` | Target specific agents (e.g., `cursor`, `claude-code`). Can be repeated. |
|
|
268
|
+
| `-n, --name <name>` | Server name override (defaults to the selected catalog entry name) |
|
|
269
|
+
| `-y, --yes` | Skip confirmation prompts |
|
|
270
|
+
| `--auto-approve` | Auto-approve MCP tool calls for supported agents (Codex, Claude Code) |
|
|
271
|
+
| `--approve-tool <tool>` | Tool to auto-approve with `--auto-approve` (repeatable; defaults to all) |
|
|
272
|
+
| `--all` | Install to all agents |
|
|
273
|
+
| `--gitignore` | Add generated config files to `.gitignore` |
|
|
220
274
|
|
|
221
275
|
Transport for `find`/`search` is inferred from registry metadata. The CLI prefers HTTP remotes when available and only falls back to SSE when HTTP is not available for the selected install context.
|
|
222
276
|
|
|
@@ -133,7 +133,7 @@ var { appSupport, vscodePath, gooseConfigPath } = getPlatformPaths();
|
|
|
133
133
|
var antigravityConfigPath = join2(
|
|
134
134
|
home,
|
|
135
135
|
".gemini",
|
|
136
|
-
"
|
|
136
|
+
"config",
|
|
137
137
|
"mcp_config.json"
|
|
138
138
|
);
|
|
139
139
|
var clineCliConfigPath = join2(
|
|
@@ -159,6 +159,41 @@ var windsurfConfigPath = join2(
|
|
|
159
159
|
"windsurf",
|
|
160
160
|
"mcp_config.json"
|
|
161
161
|
);
|
|
162
|
+
function buildStandardRemote(config) {
|
|
163
|
+
const remote = {};
|
|
164
|
+
if (config.type) remote.type = config.type;
|
|
165
|
+
if (config.url) remote.url = config.url;
|
|
166
|
+
if (config.headers && Object.keys(config.headers).length > 0) {
|
|
167
|
+
remote.headers = config.headers;
|
|
168
|
+
}
|
|
169
|
+
if (typeof config.timeout === "number") {
|
|
170
|
+
remote.timeout = config.timeout;
|
|
171
|
+
}
|
|
172
|
+
return remote;
|
|
173
|
+
}
|
|
174
|
+
function buildStandardLocal(config) {
|
|
175
|
+
const local = {
|
|
176
|
+
command: config.command,
|
|
177
|
+
args: config.args || []
|
|
178
|
+
};
|
|
179
|
+
if (config.env && Object.keys(config.env).length > 0) {
|
|
180
|
+
local.env = config.env;
|
|
181
|
+
}
|
|
182
|
+
return local;
|
|
183
|
+
}
|
|
184
|
+
function transformStandardConfig(_serverName, config) {
|
|
185
|
+
return config.url ? buildStandardRemote(config) : buildStandardLocal(config);
|
|
186
|
+
}
|
|
187
|
+
function transformGeminiConfig(_serverName, config) {
|
|
188
|
+
if (!config.url) {
|
|
189
|
+
return buildStandardLocal(config);
|
|
190
|
+
}
|
|
191
|
+
const remote = buildStandardRemote(config);
|
|
192
|
+
if (config.oauthScopes && config.oauthScopes.length > 0) {
|
|
193
|
+
remote.oauth = { scopes: config.oauthScopes };
|
|
194
|
+
}
|
|
195
|
+
return remote;
|
|
196
|
+
}
|
|
162
197
|
function transformGooseConfig(serverName, config) {
|
|
163
198
|
if (config.url) {
|
|
164
199
|
const gooseType = config.type === "sse" ? "sse" : "streamable_http";
|
|
@@ -215,6 +250,17 @@ function transformOpenCodeConfig(_serverName, config) {
|
|
|
215
250
|
environment: config.env || {}
|
|
216
251
|
};
|
|
217
252
|
}
|
|
253
|
+
function applyCodexApproval(target, autoApproveTools) {
|
|
254
|
+
if (!autoApproveTools) return target;
|
|
255
|
+
if (autoApproveTools.length === 0) {
|
|
256
|
+
target.default_tools_approval_mode = "approve";
|
|
257
|
+
return target;
|
|
258
|
+
}
|
|
259
|
+
target.tools = Object.fromEntries(
|
|
260
|
+
autoApproveTools.map((tool) => [tool, { approval_mode: "approve" }])
|
|
261
|
+
);
|
|
262
|
+
return target;
|
|
263
|
+
}
|
|
218
264
|
function transformCodexConfig(_serverName, config) {
|
|
219
265
|
if (config.url) {
|
|
220
266
|
const remoteConfig = {
|
|
@@ -224,13 +270,16 @@ function transformCodexConfig(_serverName, config) {
|
|
|
224
270
|
if (config.headers && Object.keys(config.headers).length > 0) {
|
|
225
271
|
remoteConfig.http_headers = config.headers;
|
|
226
272
|
}
|
|
227
|
-
return remoteConfig;
|
|
273
|
+
return applyCodexApproval(remoteConfig, config.autoApproveTools);
|
|
228
274
|
}
|
|
229
|
-
return
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
275
|
+
return applyCodexApproval(
|
|
276
|
+
{
|
|
277
|
+
command: config.command,
|
|
278
|
+
args: config.args || [],
|
|
279
|
+
env: config.env
|
|
280
|
+
},
|
|
281
|
+
config.autoApproveTools
|
|
282
|
+
);
|
|
234
283
|
}
|
|
235
284
|
function transformCursorConfig(_serverName, config) {
|
|
236
285
|
if (config.url) {
|
|
@@ -240,9 +289,12 @@ function transformCursorConfig(_serverName, config) {
|
|
|
240
289
|
if (config.headers && Object.keys(config.headers).length > 0) {
|
|
241
290
|
remoteConfig.headers = config.headers;
|
|
242
291
|
}
|
|
292
|
+
if (config.oauthScopes && config.oauthScopes.length > 0) {
|
|
293
|
+
remoteConfig.auth = { scopes: config.oauthScopes };
|
|
294
|
+
}
|
|
243
295
|
return remoteConfig;
|
|
244
296
|
}
|
|
245
|
-
return config;
|
|
297
|
+
return buildStandardLocal(config);
|
|
246
298
|
}
|
|
247
299
|
function transformClineConfig(_serverName, config) {
|
|
248
300
|
if (config.url) {
|
|
@@ -335,8 +387,9 @@ var agents = {
|
|
|
335
387
|
configKey: "mcpServers",
|
|
336
388
|
format: "json",
|
|
337
389
|
supportedTransports: ["stdio", "http", "sse"],
|
|
390
|
+
supportedFields: [],
|
|
338
391
|
detectGlobalInstall: async () => {
|
|
339
|
-
return existsSync(join2(home, ".gemini"));
|
|
392
|
+
return existsSync(join2(home, ".gemini", "config"));
|
|
340
393
|
},
|
|
341
394
|
transformConfig: transformAntigravityConfig
|
|
342
395
|
},
|
|
@@ -349,6 +402,7 @@ var agents = {
|
|
|
349
402
|
configKey: "mcpServers",
|
|
350
403
|
format: "json",
|
|
351
404
|
supportedTransports: ["stdio", "http", "sse"],
|
|
405
|
+
supportedFields: [],
|
|
352
406
|
detectGlobalInstall: async () => {
|
|
353
407
|
return existsSync(dirname2(clineExtensionConfigPath));
|
|
354
408
|
},
|
|
@@ -363,6 +417,7 @@ var agents = {
|
|
|
363
417
|
configKey: "mcpServers",
|
|
364
418
|
format: "json",
|
|
365
419
|
supportedTransports: ["stdio", "http", "sse"],
|
|
420
|
+
supportedFields: [],
|
|
366
421
|
detectGlobalInstall: async () => {
|
|
367
422
|
return existsSync(dirname2(clineCliConfigPath));
|
|
368
423
|
},
|
|
@@ -377,9 +432,11 @@ var agents = {
|
|
|
377
432
|
configKey: "mcpServers",
|
|
378
433
|
format: "json",
|
|
379
434
|
supportedTransports: ["stdio", "http", "sse"],
|
|
435
|
+
supportedFields: ["timeout", "autoApprove"],
|
|
380
436
|
detectGlobalInstall: async () => {
|
|
381
437
|
return existsSync(join2(home, ".claude"));
|
|
382
|
-
}
|
|
438
|
+
},
|
|
439
|
+
transformConfig: transformStandardConfig
|
|
383
440
|
},
|
|
384
441
|
"claude-desktop": {
|
|
385
442
|
name: "claude-desktop",
|
|
@@ -390,10 +447,12 @@ var agents = {
|
|
|
390
447
|
configKey: "mcpServers",
|
|
391
448
|
format: "json",
|
|
392
449
|
supportedTransports: ["stdio"],
|
|
450
|
+
supportedFields: [],
|
|
393
451
|
unsupportedTransportMessage: "Claude Desktop only supports local (stdio) servers via its config file. Add remote servers through Settings \u2192 Connectors in the app instead.",
|
|
394
452
|
detectGlobalInstall: async () => {
|
|
395
453
|
return existsSync(join2(appSupport, "Claude"));
|
|
396
|
-
}
|
|
454
|
+
},
|
|
455
|
+
transformConfig: transformStandardConfig
|
|
397
456
|
},
|
|
398
457
|
codex: {
|
|
399
458
|
name: "codex",
|
|
@@ -407,6 +466,7 @@ var agents = {
|
|
|
407
466
|
configKey: "mcp_servers",
|
|
408
467
|
format: "toml",
|
|
409
468
|
supportedTransports: ["stdio", "http", "sse"],
|
|
469
|
+
supportedFields: ["autoApprove"],
|
|
410
470
|
detectGlobalInstall: async () => {
|
|
411
471
|
return existsSync(join2(home, ".codex"));
|
|
412
472
|
},
|
|
@@ -421,6 +481,7 @@ var agents = {
|
|
|
421
481
|
configKey: "mcpServers",
|
|
422
482
|
format: "json",
|
|
423
483
|
supportedTransports: ["stdio", "http", "sse"],
|
|
484
|
+
supportedFields: ["scopes"],
|
|
424
485
|
detectGlobalInstall: async () => {
|
|
425
486
|
return existsSync(join2(home, ".cursor"));
|
|
426
487
|
},
|
|
@@ -435,9 +496,11 @@ var agents = {
|
|
|
435
496
|
configKey: "mcpServers",
|
|
436
497
|
format: "json",
|
|
437
498
|
supportedTransports: ["stdio", "http", "sse"],
|
|
499
|
+
supportedFields: ["timeout", "scopes"],
|
|
438
500
|
detectGlobalInstall: async () => {
|
|
439
501
|
return existsSync(join2(home, ".gemini"));
|
|
440
|
-
}
|
|
502
|
+
},
|
|
503
|
+
transformConfig: transformGeminiConfig
|
|
441
504
|
},
|
|
442
505
|
goose: {
|
|
443
506
|
name: "goose",
|
|
@@ -448,6 +511,7 @@ var agents = {
|
|
|
448
511
|
configKey: "extensions",
|
|
449
512
|
format: "yaml",
|
|
450
513
|
supportedTransports: ["stdio", "http", "sse"],
|
|
514
|
+
supportedFields: [],
|
|
451
515
|
detectGlobalInstall: async () => {
|
|
452
516
|
return existsSync(gooseConfigPath);
|
|
453
517
|
},
|
|
@@ -463,6 +527,7 @@ var agents = {
|
|
|
463
527
|
localConfigKey: "servers",
|
|
464
528
|
format: "json",
|
|
465
529
|
supportedTransports: ["stdio", "http", "sse"],
|
|
530
|
+
supportedFields: [],
|
|
466
531
|
detectGlobalInstall: async () => {
|
|
467
532
|
return existsSync(dirname2(copilotConfigPath));
|
|
468
533
|
},
|
|
@@ -477,10 +542,12 @@ var agents = {
|
|
|
477
542
|
configKey: "mcpServers",
|
|
478
543
|
format: "json",
|
|
479
544
|
supportedTransports: ["stdio", "http", "sse"],
|
|
545
|
+
supportedFields: [],
|
|
480
546
|
detectGlobalInstall: async () => {
|
|
481
547
|
return existsSync(join2(home, ".mcporter"));
|
|
482
548
|
},
|
|
483
|
-
resolveConfigPath: resolveMcporterConfigPath
|
|
549
|
+
resolveConfigPath: resolveMcporterConfigPath,
|
|
550
|
+
transformConfig: transformStandardConfig
|
|
484
551
|
},
|
|
485
552
|
opencode: {
|
|
486
553
|
name: "opencode",
|
|
@@ -491,6 +558,7 @@ var agents = {
|
|
|
491
558
|
configKey: "mcp",
|
|
492
559
|
format: "json",
|
|
493
560
|
supportedTransports: ["stdio", "http", "sse"],
|
|
561
|
+
supportedFields: [],
|
|
494
562
|
detectGlobalInstall: async () => {
|
|
495
563
|
return existsSync(join2(home, ".config", "opencode"));
|
|
496
564
|
},
|
|
@@ -505,9 +573,11 @@ var agents = {
|
|
|
505
573
|
configKey: "servers",
|
|
506
574
|
format: "json",
|
|
507
575
|
supportedTransports: ["stdio", "http", "sse"],
|
|
576
|
+
supportedFields: [],
|
|
508
577
|
detectGlobalInstall: async () => {
|
|
509
578
|
return existsSync(vscodePath);
|
|
510
|
-
}
|
|
579
|
+
},
|
|
580
|
+
transformConfig: transformStandardConfig
|
|
511
581
|
},
|
|
512
582
|
windsurf: {
|
|
513
583
|
name: "windsurf",
|
|
@@ -518,6 +588,7 @@ var agents = {
|
|
|
518
588
|
configKey: "mcpServers",
|
|
519
589
|
format: "json",
|
|
520
590
|
supportedTransports: ["stdio", "http", "sse"],
|
|
591
|
+
supportedFields: [],
|
|
521
592
|
detectGlobalInstall: async () => {
|
|
522
593
|
return existsSync(join2(home, ".codeium", "windsurf"));
|
|
523
594
|
},
|
|
@@ -532,6 +603,7 @@ var agents = {
|
|
|
532
603
|
configKey: "context_servers",
|
|
533
604
|
format: "json",
|
|
534
605
|
supportedTransports: ["stdio", "http", "sse"],
|
|
606
|
+
supportedFields: [],
|
|
535
607
|
detectGlobalInstall: async () => {
|
|
536
608
|
const configDir = process.platform === "darwin" || process.platform === "win32" ? join2(appSupport, "Zed") : join2(appSupport, "zed");
|
|
537
609
|
return existsSync(configDir);
|
|
@@ -1108,9 +1180,59 @@ function buildConfigWithKey(configKey, serverName, serverConfig) {
|
|
|
1108
1180
|
return config;
|
|
1109
1181
|
}
|
|
1110
1182
|
|
|
1183
|
+
// src/schema.ts
|
|
1184
|
+
var OPTIONAL_FIELD_SPECS = {
|
|
1185
|
+
timeout: {
|
|
1186
|
+
label: "request timeout",
|
|
1187
|
+
isSet: (config) => typeof config.timeout === "number",
|
|
1188
|
+
clear: (config) => {
|
|
1189
|
+
delete config.timeout;
|
|
1190
|
+
}
|
|
1191
|
+
},
|
|
1192
|
+
scopes: {
|
|
1193
|
+
label: "OAuth scopes",
|
|
1194
|
+
isSet: (config) => Array.isArray(config.oauthScopes) && config.oauthScopes.length > 0,
|
|
1195
|
+
clear: (config) => {
|
|
1196
|
+
delete config.oauthScopes;
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
autoApprove: {
|
|
1200
|
+
label: "tool auto-approval",
|
|
1201
|
+
// An empty array is meaningful ("approve all tools"), so presence alone
|
|
1202
|
+
// counts as set — unlike scopes where an empty list means "nothing".
|
|
1203
|
+
isSet: (config) => Array.isArray(config.autoApproveTools),
|
|
1204
|
+
clear: (config) => {
|
|
1205
|
+
delete config.autoApproveTools;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
var ALL_OPTIONAL_FIELDS = Object.keys(
|
|
1210
|
+
OPTIONAL_FIELD_SPECS
|
|
1211
|
+
);
|
|
1212
|
+
function describeOptionalField(field) {
|
|
1213
|
+
return OPTIONAL_FIELD_SPECS[field].label;
|
|
1214
|
+
}
|
|
1215
|
+
function applyFieldSupport(config, supportedFields) {
|
|
1216
|
+
const supported = new Set(supportedFields);
|
|
1217
|
+
const copy = { ...config };
|
|
1218
|
+
if (copy.oauthScopes) copy.oauthScopes = [...copy.oauthScopes];
|
|
1219
|
+
if (copy.autoApproveTools) copy.autoApproveTools = [...copy.autoApproveTools];
|
|
1220
|
+
const dropped = [];
|
|
1221
|
+
for (const field of ALL_OPTIONAL_FIELDS) {
|
|
1222
|
+
const spec = OPTIONAL_FIELD_SPECS[field];
|
|
1223
|
+
if (spec.isSet(copy) && !supported.has(field)) {
|
|
1224
|
+
spec.clear(copy);
|
|
1225
|
+
dropped.push(field);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
return { config: copy, dropped };
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1111
1231
|
// src/installer.ts
|
|
1112
1232
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1233
|
+
import { homedir as homedir3 } from "os";
|
|
1113
1234
|
import { join as join3, dirname as dirname6, isAbsolute, relative, sep } from "path";
|
|
1235
|
+
var home2 = homedir3();
|
|
1114
1236
|
function buildServerConfig(parsed, options = {}) {
|
|
1115
1237
|
if (parsed.type === "remote") {
|
|
1116
1238
|
const config2 = {
|
|
@@ -1120,6 +1242,15 @@ function buildServerConfig(parsed, options = {}) {
|
|
|
1120
1242
|
if (options.headers && Object.keys(options.headers).length > 0) {
|
|
1121
1243
|
config2.headers = options.headers;
|
|
1122
1244
|
}
|
|
1245
|
+
if (typeof options.timeout === "number") {
|
|
1246
|
+
config2.timeout = options.timeout;
|
|
1247
|
+
}
|
|
1248
|
+
if (options.oauthScopes && options.oauthScopes.length > 0) {
|
|
1249
|
+
config2.oauthScopes = options.oauthScopes;
|
|
1250
|
+
}
|
|
1251
|
+
if (options.autoApproveTools) {
|
|
1252
|
+
config2.autoApproveTools = options.autoApproveTools;
|
|
1253
|
+
}
|
|
1123
1254
|
return config2;
|
|
1124
1255
|
}
|
|
1125
1256
|
if (parsed.type === "command") {
|
|
@@ -1141,6 +1272,9 @@ function buildServerConfig(parsed, options = {}) {
|
|
|
1141
1272
|
if (options.env && Object.keys(options.env).length > 0) {
|
|
1142
1273
|
config2.env = options.env;
|
|
1143
1274
|
}
|
|
1275
|
+
if (options.autoApproveTools) {
|
|
1276
|
+
config2.autoApproveTools = options.autoApproveTools;
|
|
1277
|
+
}
|
|
1144
1278
|
return config2;
|
|
1145
1279
|
}
|
|
1146
1280
|
const config = {
|
|
@@ -1150,8 +1284,66 @@ function buildServerConfig(parsed, options = {}) {
|
|
|
1150
1284
|
if (options.env && Object.keys(options.env).length > 0) {
|
|
1151
1285
|
config.env = options.env;
|
|
1152
1286
|
}
|
|
1287
|
+
if (options.autoApproveTools) {
|
|
1288
|
+
config.autoApproveTools = options.autoApproveTools;
|
|
1289
|
+
}
|
|
1153
1290
|
return config;
|
|
1154
1291
|
}
|
|
1292
|
+
function readJsonObject(filePath) {
|
|
1293
|
+
if (!existsSync5(filePath)) {
|
|
1294
|
+
return {};
|
|
1295
|
+
}
|
|
1296
|
+
const parsed = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
1297
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
1298
|
+
}
|
|
1299
|
+
function writeJsonObject(filePath, value) {
|
|
1300
|
+
const dir = dirname6(filePath);
|
|
1301
|
+
if (!existsSync5(dir)) {
|
|
1302
|
+
mkdirSync4(dir, { recursive: true });
|
|
1303
|
+
}
|
|
1304
|
+
writeFileSync4(filePath, `${JSON.stringify(value, null, 2)}
|
|
1305
|
+
`, "utf-8");
|
|
1306
|
+
}
|
|
1307
|
+
function addUniqueStrings(existing, additions) {
|
|
1308
|
+
const values = Array.isArray(existing) ? existing.filter((value) => typeof value === "string") : [];
|
|
1309
|
+
for (const addition of additions) {
|
|
1310
|
+
if (!values.includes(addition)) {
|
|
1311
|
+
values.push(addition);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
return values;
|
|
1315
|
+
}
|
|
1316
|
+
function claudeAutoApproveRules(serverName, tools) {
|
|
1317
|
+
if (tools.length === 0) {
|
|
1318
|
+
return [`mcp__${serverName}`];
|
|
1319
|
+
}
|
|
1320
|
+
return tools.map((tool) => `mcp__${serverName}__${tool}`);
|
|
1321
|
+
}
|
|
1322
|
+
function getClaudeCodeSettingsPath(options = {}) {
|
|
1323
|
+
const local = Boolean(options.local);
|
|
1324
|
+
const cwd = options.cwd || process.cwd();
|
|
1325
|
+
return local ? join3(cwd, ".claude", "settings.local.json") : join3(home2, ".claude", "settings.json");
|
|
1326
|
+
}
|
|
1327
|
+
function installClaudeCodeAutoApproval(serverName, tools, options = {}) {
|
|
1328
|
+
const settingsPath = getClaudeCodeSettingsPath(options);
|
|
1329
|
+
try {
|
|
1330
|
+
const settings = readJsonObject(settingsPath);
|
|
1331
|
+
const permissions = settings.permissions && typeof settings.permissions === "object" && !Array.isArray(settings.permissions) ? settings.permissions : {};
|
|
1332
|
+
permissions.allow = addUniqueStrings(
|
|
1333
|
+
permissions.allow,
|
|
1334
|
+
claudeAutoApproveRules(serverName, tools)
|
|
1335
|
+
);
|
|
1336
|
+
settings.permissions = permissions;
|
|
1337
|
+
writeJsonObject(settingsPath, settings);
|
|
1338
|
+
return { success: true, path: settingsPath };
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
return {
|
|
1341
|
+
success: false,
|
|
1342
|
+
path: settingsPath,
|
|
1343
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1155
1347
|
function updateGitignoreWithPaths(paths, options = {}) {
|
|
1156
1348
|
const cwd = options.cwd || process.cwd();
|
|
1157
1349
|
const gitignorePath = join3(cwd, ".gitignore");
|
|
@@ -1212,15 +1404,37 @@ function installServerForAgent(serverName, serverConfig, agentType, options = {}
|
|
|
1212
1404
|
if (!existsSync5(dir)) {
|
|
1213
1405
|
mkdirSync4(dir, { recursive: true });
|
|
1214
1406
|
}
|
|
1215
|
-
const
|
|
1407
|
+
const { config: gatedConfig, dropped } = applyFieldSupport(
|
|
1408
|
+
serverConfig,
|
|
1409
|
+
agent.supportedFields
|
|
1410
|
+
);
|
|
1411
|
+
const transformedConfig = agent.transformConfig(serverName, gatedConfig, {
|
|
1216
1412
|
local: Boolean(options.local)
|
|
1217
|
-
})
|
|
1413
|
+
});
|
|
1218
1414
|
const configKey = getConfigKey(agent, options);
|
|
1219
1415
|
const config = buildConfigWithKey(configKey, serverName, transformedConfig);
|
|
1220
1416
|
writeConfig2(configPath, config, agent.format, configKey);
|
|
1417
|
+
const extraPaths = [];
|
|
1418
|
+
if (agentType === "claude-code" && gatedConfig.autoApproveTools) {
|
|
1419
|
+
const approval = installClaudeCodeAutoApproval(
|
|
1420
|
+
serverName,
|
|
1421
|
+
gatedConfig.autoApproveTools,
|
|
1422
|
+
options
|
|
1423
|
+
);
|
|
1424
|
+
if (!approval.success) {
|
|
1425
|
+
return {
|
|
1426
|
+
success: false,
|
|
1427
|
+
path: approval.path,
|
|
1428
|
+
error: approval.error
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
extraPaths.push(approval.path);
|
|
1432
|
+
}
|
|
1221
1433
|
return {
|
|
1222
1434
|
success: true,
|
|
1223
|
-
path: configPath
|
|
1435
|
+
path: configPath,
|
|
1436
|
+
...dropped.length > 0 ? { droppedFields: dropped } : {},
|
|
1437
|
+
...extraPaths.length > 0 ? { extraPaths } : {}
|
|
1224
1438
|
};
|
|
1225
1439
|
} catch (error) {
|
|
1226
1440
|
return {
|
|
@@ -1384,6 +1598,7 @@ export {
|
|
|
1384
1598
|
getNestedValue,
|
|
1385
1599
|
readConfig2 as readConfig,
|
|
1386
1600
|
removeServerFromConfig,
|
|
1601
|
+
describeOptionalField,
|
|
1387
1602
|
buildServerConfig,
|
|
1388
1603
|
updateGitignoreWithPaths,
|
|
1389
1604
|
getConfigPath2,
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
agents,
|
|
4
4
|
buildAgentSelectionChoices,
|
|
5
5
|
buildServerConfig,
|
|
6
|
+
describeOptionalField,
|
|
6
7
|
detectGlobalAgents,
|
|
7
8
|
detectProjectAgents,
|
|
8
9
|
findMatchingServers,
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
selectAgentsInteractive,
|
|
23
24
|
supportsProjectConfig,
|
|
24
25
|
updateGitignoreWithPaths
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-IPCKQUBH.js";
|
|
26
27
|
|
|
27
28
|
// src/index.ts
|
|
28
29
|
import { program } from "commander";
|
|
@@ -782,7 +783,7 @@ async function runFind(query, options) {
|
|
|
782
783
|
// package.json
|
|
783
784
|
var package_default = {
|
|
784
785
|
name: "add-mcp",
|
|
785
|
-
version: "1.
|
|
786
|
+
version: "1.12.0",
|
|
786
787
|
description: "Add MCP servers to your favorite coding agents with a single command.",
|
|
787
788
|
author: "Andre Landgraf <andre@neon.tech>",
|
|
788
789
|
license: "Apache-2.0",
|
|
@@ -973,6 +974,25 @@ function extractSubcommandOptionsFromArgv() {
|
|
|
973
974
|
result.gitignore = true;
|
|
974
975
|
continue;
|
|
975
976
|
}
|
|
977
|
+
if (arg === "--auto-approve") {
|
|
978
|
+
result.autoApprove = true;
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
if (arg === "--approve-tool") {
|
|
982
|
+
const tools = result.approveTool ? [...result.approveTool] : [];
|
|
983
|
+
let j = i + 1;
|
|
984
|
+
while (j < argv.length) {
|
|
985
|
+
const value = argv[j];
|
|
986
|
+
if (!value || value.startsWith("-")) break;
|
|
987
|
+
tools.push(value);
|
|
988
|
+
j += 1;
|
|
989
|
+
}
|
|
990
|
+
if (tools.length > 0) {
|
|
991
|
+
result.approveTool = tools;
|
|
992
|
+
}
|
|
993
|
+
i = j - 1;
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
976
996
|
if ((arg === "-h" || arg === "--header") && argv[i + 1]) {
|
|
977
997
|
const headers = result.header ? [...result.header] : [];
|
|
978
998
|
headers.push(argv[i + 1]);
|
|
@@ -1119,6 +1139,20 @@ program.name("add-mcp").description(
|
|
|
1119
1139
|
"Argument for local stdio servers (repeatable). Placeholders ${VAR} prompt interactively when not using --yes. Use single quotes so your shell does not expand the ${VAR}.",
|
|
1120
1140
|
collect,
|
|
1121
1141
|
[]
|
|
1142
|
+
).option(
|
|
1143
|
+
"--timeout <ms>",
|
|
1144
|
+
"Request timeout in milliseconds for remote servers. Only applied to agents that support it (e.g. Claude Code, Gemini CLI); dropped with a warning elsewhere."
|
|
1145
|
+
).option(
|
|
1146
|
+
"--scopes <scopes>",
|
|
1147
|
+
"OAuth scopes to request for remote servers (comma-separated). Only applied to agents that support it (e.g. Cursor, Gemini CLI); dropped with a warning elsewhere."
|
|
1148
|
+
).option("--oauth-scopes <scopes>", "Alias for --scopes").option(
|
|
1149
|
+
"--auto-approve",
|
|
1150
|
+
"Auto-approve MCP tool calls for agents that support it (Codex, Claude Code). Dropped with a warning for other agents."
|
|
1151
|
+
).option(
|
|
1152
|
+
"--approve-tool <tool>",
|
|
1153
|
+
"Tool name to auto-approve when --auto-approve is set (repeatable; defaults to all tools)",
|
|
1154
|
+
collect,
|
|
1155
|
+
[]
|
|
1122
1156
|
).option("-y, --yes", "Skip confirmation prompts").option("--all", "Install to all agents").option("--gitignore", "Add generated project config files to .gitignore").action(async (target, options) => {
|
|
1123
1157
|
await main(target, options);
|
|
1124
1158
|
});
|
|
@@ -1165,7 +1199,15 @@ program.command("find [keyword]").description(
|
|
|
1165
1199
|
).option("-a, --agent <agent>", "Specify agents to install to", collect, []).option(
|
|
1166
1200
|
"-n, --name <name>",
|
|
1167
1201
|
"Server name override (defaults to catalog entry name)"
|
|
1168
|
-
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1202
|
+
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1203
|
+
"--auto-approve",
|
|
1204
|
+
"Auto-approve MCP tool calls for agents that support it (Codex, Claude Code)"
|
|
1205
|
+
).option(
|
|
1206
|
+
"--approve-tool <tool>",
|
|
1207
|
+
"Tool name to auto-approve when --auto-approve is set (repeatable; defaults to all tools)",
|
|
1208
|
+
collect,
|
|
1209
|
+
[]
|
|
1210
|
+
).option("--all", "Install to all agents").option("--gitignore", "Add generated project config files to .gitignore").action(
|
|
1169
1211
|
async (keyword, options) => {
|
|
1170
1212
|
await runFindCommand(keyword, options);
|
|
1171
1213
|
}
|
|
@@ -1176,7 +1218,15 @@ program.command("search [keyword]").description("Alias for find").option(
|
|
|
1176
1218
|
).option("-a, --agent <agent>", "Specify agents to install to", collect, []).option(
|
|
1177
1219
|
"-n, --name <name>",
|
|
1178
1220
|
"Server name override (defaults to catalog entry name)"
|
|
1179
|
-
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1221
|
+
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1222
|
+
"--auto-approve",
|
|
1223
|
+
"Auto-approve MCP tool calls for agents that support it (Codex, Claude Code)"
|
|
1224
|
+
).option(
|
|
1225
|
+
"--approve-tool <tool>",
|
|
1226
|
+
"Tool name to auto-approve when --auto-approve is set (repeatable; defaults to all tools)",
|
|
1227
|
+
collect,
|
|
1228
|
+
[]
|
|
1229
|
+
).option("--all", "Install to all agents").option("--gitignore", "Add generated project config files to .gitignore").action(
|
|
1180
1230
|
async (keyword, options) => {
|
|
1181
1231
|
await runFindCommand(keyword, options);
|
|
1182
1232
|
}
|
|
@@ -1791,11 +1841,47 @@ async function main(target, options) {
|
|
|
1791
1841
|
p2.log.warn("--transport is only used for remote URLs, ignoring");
|
|
1792
1842
|
}
|
|
1793
1843
|
}
|
|
1844
|
+
let resolvedTimeout;
|
|
1845
|
+
if (options.timeout !== void 0) {
|
|
1846
|
+
const parsedTimeout = Number(options.timeout);
|
|
1847
|
+
if (!Number.isInteger(parsedTimeout) || parsedTimeout <= 0) {
|
|
1848
|
+
p2.log.error(
|
|
1849
|
+
`Invalid --timeout value: ${options.timeout}. Provide a positive integer (milliseconds).`
|
|
1850
|
+
);
|
|
1851
|
+
process.exit(1);
|
|
1852
|
+
}
|
|
1853
|
+
if (isRemote) {
|
|
1854
|
+
resolvedTimeout = parsedTimeout;
|
|
1855
|
+
} else {
|
|
1856
|
+
p2.log.warn("--timeout is only used for remote URLs, ignoring");
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
const scopesValue = options.scopes ?? options.oauthScopes;
|
|
1860
|
+
let resolvedScopes;
|
|
1861
|
+
if (scopesValue !== void 0) {
|
|
1862
|
+
const parsedScopes = scopesValue.split(",").map((scope) => scope.trim()).filter((scope) => scope.length > 0);
|
|
1863
|
+
if (parsedScopes.length === 0) {
|
|
1864
|
+
p2.log.error(
|
|
1865
|
+
`Invalid --scopes value: ${scopesValue}. Provide one or more comma-separated scopes.`
|
|
1866
|
+
);
|
|
1867
|
+
process.exit(1);
|
|
1868
|
+
}
|
|
1869
|
+
if (isRemote) {
|
|
1870
|
+
resolvedScopes = parsedScopes;
|
|
1871
|
+
} else {
|
|
1872
|
+
p2.log.warn("--scopes is only used for remote URLs, ignoring");
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
const approveTools = [...new Set(options.approveTool ?? [])];
|
|
1876
|
+
const autoApproveTools = options.autoApprove || approveTools.length > 0 ? approveTools : void 0;
|
|
1794
1877
|
const serverConfig = buildServerConfig(parsed, {
|
|
1795
1878
|
transport: resolvedTransport,
|
|
1796
1879
|
headers: headersForConfig && Object.keys(headersForConfig).length > 0 ? headersForConfig : void 0,
|
|
1797
1880
|
env: envForConfig && Object.keys(envForConfig).length > 0 ? envForConfig : void 0,
|
|
1798
|
-
args: argsForConfig && argsForConfig.length > 0 ? argsForConfig : void 0
|
|
1881
|
+
args: argsForConfig && argsForConfig.length > 0 ? argsForConfig : void 0,
|
|
1882
|
+
timeout: resolvedTimeout,
|
|
1883
|
+
oauthScopes: resolvedScopes,
|
|
1884
|
+
autoApproveTools
|
|
1799
1885
|
});
|
|
1800
1886
|
let targetAgents;
|
|
1801
1887
|
const allAgentTypes = getAgentTypes();
|
|
@@ -1991,6 +2077,11 @@ async function main(target, options) {
|
|
|
1991
2077
|
const summaryLines = [];
|
|
1992
2078
|
summaryLines.push(`${chalk.cyan("Server:")} ${serverName}`);
|
|
1993
2079
|
summaryLines.push(`${chalk.cyan("Type:")} ${sourceType}`);
|
|
2080
|
+
if (autoApproveTools) {
|
|
2081
|
+
summaryLines.push(
|
|
2082
|
+
`${chalk.cyan("Auto-approve:")} ${autoApproveTools.length === 0 ? "All tools" : autoApproveTools.join(", ")}`
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
1994
2085
|
const localAgents = targetAgents.filter(
|
|
1995
2086
|
(a) => agentRouting.get(a) === "local"
|
|
1996
2087
|
);
|
|
@@ -2043,6 +2134,11 @@ async function main(target, options) {
|
|
|
2043
2134
|
resultLines.push(
|
|
2044
2135
|
`${chalk.green("\u2713")} ${agent.displayName}: ${chalk.dim(shortPath)}`
|
|
2045
2136
|
);
|
|
2137
|
+
for (const extraPath of result.extraPaths ?? []) {
|
|
2138
|
+
resultLines.push(
|
|
2139
|
+
` ${chalk.dim("\u21B3 permissions:")} ${chalk.dim(shortenPath(extraPath))}`
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2046
2142
|
}
|
|
2047
2143
|
p2.note(
|
|
2048
2144
|
resultLines.join("\n"),
|
|
@@ -2065,12 +2161,28 @@ async function main(target, options) {
|
|
|
2065
2161
|
);
|
|
2066
2162
|
}
|
|
2067
2163
|
}
|
|
2164
|
+
const droppedByField = /* @__PURE__ */ new Map();
|
|
2165
|
+
for (const [agentType, result] of results) {
|
|
2166
|
+
for (const field of result.droppedFields ?? []) {
|
|
2167
|
+
const agentNames = droppedByField.get(field) ?? [];
|
|
2168
|
+
agentNames.push(agents[agentType].displayName);
|
|
2169
|
+
droppedByField.set(field, agentNames);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
for (const [field, agentNames] of droppedByField) {
|
|
2173
|
+
p2.log.warn(
|
|
2174
|
+
`${describeOptionalField(field)} is not supported by ${agentNames.join(", ")}; dropped from ${agentNames.length === 1 ? "that config" : "those configs"}.`
|
|
2175
|
+
);
|
|
2176
|
+
}
|
|
2068
2177
|
if (options.gitignore && options.global) {
|
|
2069
2178
|
p2.log.warn(
|
|
2070
2179
|
"--gitignore is only supported for project-scoped installations; ignoring."
|
|
2071
2180
|
);
|
|
2072
2181
|
} else if (options.gitignore) {
|
|
2073
|
-
const successfulPaths = successful.
|
|
2182
|
+
const successfulPaths = successful.flatMap(([_, result]) => [
|
|
2183
|
+
result.path,
|
|
2184
|
+
...result.extraPaths ?? []
|
|
2185
|
+
]);
|
|
2074
2186
|
const gitignoreUpdate = updateGitignoreWithPaths(successfulPaths);
|
|
2075
2187
|
if (gitignoreUpdate.added.length > 0) {
|
|
2076
2188
|
p2.log.info(
|
package/dist/lib.d.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional, capability-gated fields on {@link McpServerConfig}.
|
|
3
|
+
*
|
|
4
|
+
* The canonical {@link McpServerConfig} is the single, agent-agnostic schema
|
|
5
|
+
* that the CLI and library populate. Not every MCP client understands every
|
|
6
|
+
* optional field, so each agent declares which of these it supports via
|
|
7
|
+
* `AgentConfig.supportedFields`. Anything an agent does not support is dropped
|
|
8
|
+
* before its transform runs, guaranteeing that only known fields are ever
|
|
9
|
+
* written to a client config.
|
|
10
|
+
*/
|
|
11
|
+
type OptionalField = "timeout" | "scopes" | "autoApprove";
|
|
12
|
+
|
|
1
13
|
type AgentType = "antigravity" | "cline" | "cline-cli" | "claude-code" | "claude-desktop" | "codex" | "cursor" | "gemini-cli" | "goose" | "github-copilot-cli" | "mcporter" | "opencode" | "vscode" | "windsurf" | "zed";
|
|
2
14
|
type ConfigFormat = "json" | "yaml" | "toml";
|
|
3
15
|
interface AgentConfig {
|
|
@@ -19,6 +31,14 @@ interface AgentConfig {
|
|
|
19
31
|
format: ConfigFormat;
|
|
20
32
|
/** Supported transport types for this agent */
|
|
21
33
|
supportedTransports: ("stdio" | "sse" | "http")[];
|
|
34
|
+
/**
|
|
35
|
+
* Optional, capability-gated server fields this agent understands (e.g.
|
|
36
|
+
* `timeout`, `scopes`). Any optional field not listed here is stripped from
|
|
37
|
+
* the canonical config before {@link transformConfig} runs, so a client never
|
|
38
|
+
* receives a field it cannot interpret. Use an empty array for agents that
|
|
39
|
+
* only support the core fields.
|
|
40
|
+
*/
|
|
41
|
+
supportedFields: OptionalField[];
|
|
22
42
|
/** Shown when a user tries to use an unsupported transport */
|
|
23
43
|
unsupportedTransportMessage?: string;
|
|
24
44
|
/** Function to detect if agent is installed globally */
|
|
@@ -28,8 +48,13 @@ interface AgentConfig {
|
|
|
28
48
|
local: boolean;
|
|
29
49
|
cwd: string;
|
|
30
50
|
}) => string;
|
|
31
|
-
/**
|
|
32
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Transform the canonical, field-gated server config into this agent's
|
|
53
|
+
* concrete on-disk schema. Required for every agent: transforms must build a
|
|
54
|
+
* fresh object with only the keys the client understands, which structurally
|
|
55
|
+
* guarantees no unknown fields leak into a written config.
|
|
56
|
+
*/
|
|
57
|
+
transformConfig: (serverName: string, config: McpServerConfig, context?: {
|
|
33
58
|
local: boolean;
|
|
34
59
|
}) => unknown;
|
|
35
60
|
}
|
|
@@ -43,6 +68,26 @@ interface McpServerConfig {
|
|
|
43
68
|
command?: string;
|
|
44
69
|
args?: string[];
|
|
45
70
|
env?: Record<string, string>;
|
|
71
|
+
/**
|
|
72
|
+
* Request timeout in milliseconds for remote servers. Capability-gated:
|
|
73
|
+
* only emitted for agents that list `"timeout"` in `supportedFields`.
|
|
74
|
+
*/
|
|
75
|
+
timeout?: number;
|
|
76
|
+
/**
|
|
77
|
+
* OAuth scopes to request for remote servers. Capability-gated: only emitted
|
|
78
|
+
* for agents that list `"scopes"` in `supportedFields`, each mapping it into
|
|
79
|
+
* their own native shape (e.g. Cursor `auth.scopes`, Gemini `oauth.scopes`).
|
|
80
|
+
*/
|
|
81
|
+
oauthScopes?: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Tools to auto-approve (skip the agent's per-call approval prompt). An empty
|
|
84
|
+
* array means "all tools". This is an install directive rather than a literal
|
|
85
|
+
* server-config key: capability-gated via `"autoApprove"` in `supportedFields`
|
|
86
|
+
* and each supporting agent applies it in its own way (e.g. Codex emits
|
|
87
|
+
* approval modes in its config; Claude Code writes permission allow rules to a
|
|
88
|
+
* separate settings file). It is never written into a server entry verbatim.
|
|
89
|
+
*/
|
|
90
|
+
autoApproveTools?: string[];
|
|
46
91
|
}
|
|
47
92
|
|
|
48
93
|
interface InstallOptions {
|
|
@@ -55,6 +100,17 @@ interface InstallResult {
|
|
|
55
100
|
success: boolean;
|
|
56
101
|
path: string;
|
|
57
102
|
error?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Optional fields that were requested but dropped because the target agent
|
|
105
|
+
* does not support them. Empty/undefined when nothing was dropped.
|
|
106
|
+
*/
|
|
107
|
+
droppedFields?: OptionalField[];
|
|
108
|
+
/**
|
|
109
|
+
* Additional files written beyond the main config (e.g. a Claude Code
|
|
110
|
+
* permissions settings file for auto-approval). Surfaced so the CLI can
|
|
111
|
+
* report them and include them in `--gitignore`.
|
|
112
|
+
*/
|
|
113
|
+
extraPaths?: string[];
|
|
58
114
|
}
|
|
59
115
|
|
|
60
116
|
declare const agents: Record<AgentType, AgentConfig>;
|
|
@@ -99,4 +155,4 @@ interface RemoveServerResult {
|
|
|
99
155
|
}
|
|
100
156
|
declare function removeServer(agentType: AgentInput, serverName: string, options?: InstallOptions): RemoveServerResult;
|
|
101
157
|
|
|
102
|
-
export { type AgentConfig, type AgentInput, type AgentServers, type AgentType, type InstallOptions, type InstallResult, type InstalledServer, type McpServerConfig, type RemoveServerResult, agents, detectGlobalAgents, detectProjectAgents, getAgentTypes, listInstalledServers, removeServer, upsertServer };
|
|
158
|
+
export { type AgentConfig, type AgentInput, type AgentServers, type AgentType, type InstallOptions, type InstallResult, type InstalledServer, type McpServerConfig, type OptionalField, type RemoveServerResult, agents, detectGlobalAgents, detectProjectAgents, getAgentTypes, listInstalledServers, removeServer, upsertServer };
|
package/dist/lib.js
CHANGED