add-mcp 1.11.0 → 1.13.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 +60 -29
- package/dist/{chunk-2OCTBM45.js → chunk-3ZFFEEQJ.js} +126 -11
- package/dist/index.js +104 -67
- package/dist/lib.d.ts +16 -1
- 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` |
|
|
@@ -128,6 +128,12 @@ npx add-mcp https://mcp.example.com/mcp --header "Authorization: Bearer $TOKEN"
|
|
|
128
128
|
# (each agent only keeps the fields it supports; others are dropped with a warning)
|
|
129
129
|
npx add-mcp https://mcp.example.com/mcp --timeout 30000 --scopes "read,write"
|
|
130
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
|
+
|
|
131
137
|
# npm package (runs via npx)
|
|
132
138
|
npx add-mcp @modelcontextprotocol/server-postgres
|
|
133
139
|
|
|
@@ -164,21 +170,23 @@ npx add-mcp https://mcp.example.com/mcp -a cursor -y --gitignore
|
|
|
164
170
|
|
|
165
171
|
### Options
|
|
166
172
|
|
|
167
|
-
| Option
|
|
168
|
-
|
|
|
169
|
-
| `-g, --global`
|
|
170
|
-
| `-a, --agent <agent>`
|
|
171
|
-
| `-t, --transport <type>`
|
|
172
|
-
| `--type <type>`
|
|
173
|
-
| `-h, --header <header>`
|
|
174
|
-
| `--env <env>`
|
|
175
|
-
| `--timeout <ms>`
|
|
176
|
-
| `--scopes <scopes>`
|
|
177
|
-
| `--oauth-scopes <scopes
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
|
|
|
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` |
|
|
182
190
|
|
|
183
191
|
#### Capability-gated fields (`--timeout`, `--scopes`)
|
|
184
192
|
|
|
@@ -186,15 +194,36 @@ Not every MCP client understands every field. `add-mcp` keeps one canonical
|
|
|
186
194
|
server config and each agent declares which optional fields it supports, mapping
|
|
187
195
|
them into that client's native shape:
|
|
188
196
|
|
|
189
|
-
| Field
|
|
190
|
-
|
|
|
191
|
-
| Timeout
|
|
192
|
-
| OAuth scopes
|
|
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 |
|
|
193
202
|
|
|
194
203
|
When you target an agent that does not support a field, `add-mcp` drops it from
|
|
195
204
|
that agent's config and prints a warning (e.g. _"request timeout is not
|
|
196
205
|
supported by VS Code; dropped from that config."_). Other agents still receive
|
|
197
|
-
it.
|
|
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.
|
|
198
227
|
|
|
199
228
|
### Transport Types
|
|
200
229
|
|
|
@@ -232,14 +261,16 @@ npx add-mcp find github --all --gitignore
|
|
|
232
261
|
|
|
233
262
|
### Options
|
|
234
263
|
|
|
235
|
-
| Option
|
|
236
|
-
|
|
|
237
|
-
| `-g, --global`
|
|
238
|
-
| `-a, --agent <agent>`
|
|
239
|
-
| `-n, --name <name>`
|
|
240
|
-
| `-y, --yes`
|
|
241
|
-
| `--
|
|
242
|
-
| `--
|
|
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` |
|
|
243
274
|
|
|
244
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.
|
|
245
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(
|
|
@@ -250,6 +250,17 @@ function transformOpenCodeConfig(_serverName, config) {
|
|
|
250
250
|
environment: config.env || {}
|
|
251
251
|
};
|
|
252
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
|
+
}
|
|
253
264
|
function transformCodexConfig(_serverName, config) {
|
|
254
265
|
if (config.url) {
|
|
255
266
|
const remoteConfig = {
|
|
@@ -259,13 +270,16 @@ function transformCodexConfig(_serverName, config) {
|
|
|
259
270
|
if (config.headers && Object.keys(config.headers).length > 0) {
|
|
260
271
|
remoteConfig.http_headers = config.headers;
|
|
261
272
|
}
|
|
262
|
-
return remoteConfig;
|
|
273
|
+
return applyCodexApproval(remoteConfig, config.autoApproveTools);
|
|
263
274
|
}
|
|
264
|
-
return
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
275
|
+
return applyCodexApproval(
|
|
276
|
+
{
|
|
277
|
+
command: config.command,
|
|
278
|
+
args: config.args || [],
|
|
279
|
+
env: config.env
|
|
280
|
+
},
|
|
281
|
+
config.autoApproveTools
|
|
282
|
+
);
|
|
269
283
|
}
|
|
270
284
|
function transformCursorConfig(_serverName, config) {
|
|
271
285
|
if (config.url) {
|
|
@@ -375,7 +389,7 @@ var agents = {
|
|
|
375
389
|
supportedTransports: ["stdio", "http", "sse"],
|
|
376
390
|
supportedFields: [],
|
|
377
391
|
detectGlobalInstall: async () => {
|
|
378
|
-
return existsSync(join2(home, ".gemini"));
|
|
392
|
+
return existsSync(join2(home, ".gemini", "config"));
|
|
379
393
|
},
|
|
380
394
|
transformConfig: transformAntigravityConfig
|
|
381
395
|
},
|
|
@@ -418,7 +432,7 @@ var agents = {
|
|
|
418
432
|
configKey: "mcpServers",
|
|
419
433
|
format: "json",
|
|
420
434
|
supportedTransports: ["stdio", "http", "sse"],
|
|
421
|
-
supportedFields: ["timeout"],
|
|
435
|
+
supportedFields: ["timeout", "autoApprove"],
|
|
422
436
|
detectGlobalInstall: async () => {
|
|
423
437
|
return existsSync(join2(home, ".claude"));
|
|
424
438
|
},
|
|
@@ -452,7 +466,7 @@ var agents = {
|
|
|
452
466
|
configKey: "mcp_servers",
|
|
453
467
|
format: "toml",
|
|
454
468
|
supportedTransports: ["stdio", "http", "sse"],
|
|
455
|
-
supportedFields: [],
|
|
469
|
+
supportedFields: ["autoApprove"],
|
|
456
470
|
detectGlobalInstall: async () => {
|
|
457
471
|
return existsSync(join2(home, ".codex"));
|
|
458
472
|
},
|
|
@@ -603,6 +617,13 @@ function getAgentTypes() {
|
|
|
603
617
|
function supportsProjectConfig(agentType) {
|
|
604
618
|
return agents[agentType].localConfigPath !== void 0;
|
|
605
619
|
}
|
|
620
|
+
function getCommonInstallScopes(agentTypes) {
|
|
621
|
+
if (agentTypes.length === 0) return [];
|
|
622
|
+
if (agentTypes.some((agentType) => !supportsProjectConfig(agentType))) {
|
|
623
|
+
return ["global"];
|
|
624
|
+
}
|
|
625
|
+
return ["local", "global"];
|
|
626
|
+
}
|
|
606
627
|
function getProjectCapableAgents() {
|
|
607
628
|
return Object.keys(agents).filter(
|
|
608
629
|
(type) => supportsProjectConfig(type)
|
|
@@ -1181,6 +1202,15 @@ var OPTIONAL_FIELD_SPECS = {
|
|
|
1181
1202
|
clear: (config) => {
|
|
1182
1203
|
delete config.oauthScopes;
|
|
1183
1204
|
}
|
|
1205
|
+
},
|
|
1206
|
+
autoApprove: {
|
|
1207
|
+
label: "tool auto-approval",
|
|
1208
|
+
// An empty array is meaningful ("approve all tools"), so presence alone
|
|
1209
|
+
// counts as set — unlike scopes where an empty list means "nothing".
|
|
1210
|
+
isSet: (config) => Array.isArray(config.autoApproveTools),
|
|
1211
|
+
clear: (config) => {
|
|
1212
|
+
delete config.autoApproveTools;
|
|
1213
|
+
}
|
|
1184
1214
|
}
|
|
1185
1215
|
};
|
|
1186
1216
|
var ALL_OPTIONAL_FIELDS = Object.keys(
|
|
@@ -1193,6 +1223,7 @@ function applyFieldSupport(config, supportedFields) {
|
|
|
1193
1223
|
const supported = new Set(supportedFields);
|
|
1194
1224
|
const copy = { ...config };
|
|
1195
1225
|
if (copy.oauthScopes) copy.oauthScopes = [...copy.oauthScopes];
|
|
1226
|
+
if (copy.autoApproveTools) copy.autoApproveTools = [...copy.autoApproveTools];
|
|
1196
1227
|
const dropped = [];
|
|
1197
1228
|
for (const field of ALL_OPTIONAL_FIELDS) {
|
|
1198
1229
|
const spec = OPTIONAL_FIELD_SPECS[field];
|
|
@@ -1206,7 +1237,9 @@ function applyFieldSupport(config, supportedFields) {
|
|
|
1206
1237
|
|
|
1207
1238
|
// src/installer.ts
|
|
1208
1239
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1240
|
+
import { homedir as homedir3 } from "os";
|
|
1209
1241
|
import { join as join3, dirname as dirname6, isAbsolute, relative, sep } from "path";
|
|
1242
|
+
var home2 = homedir3();
|
|
1210
1243
|
function buildServerConfig(parsed, options = {}) {
|
|
1211
1244
|
if (parsed.type === "remote") {
|
|
1212
1245
|
const config2 = {
|
|
@@ -1222,6 +1255,9 @@ function buildServerConfig(parsed, options = {}) {
|
|
|
1222
1255
|
if (options.oauthScopes && options.oauthScopes.length > 0) {
|
|
1223
1256
|
config2.oauthScopes = options.oauthScopes;
|
|
1224
1257
|
}
|
|
1258
|
+
if (options.autoApproveTools) {
|
|
1259
|
+
config2.autoApproveTools = options.autoApproveTools;
|
|
1260
|
+
}
|
|
1225
1261
|
return config2;
|
|
1226
1262
|
}
|
|
1227
1263
|
if (parsed.type === "command") {
|
|
@@ -1243,6 +1279,9 @@ function buildServerConfig(parsed, options = {}) {
|
|
|
1243
1279
|
if (options.env && Object.keys(options.env).length > 0) {
|
|
1244
1280
|
config2.env = options.env;
|
|
1245
1281
|
}
|
|
1282
|
+
if (options.autoApproveTools) {
|
|
1283
|
+
config2.autoApproveTools = options.autoApproveTools;
|
|
1284
|
+
}
|
|
1246
1285
|
return config2;
|
|
1247
1286
|
}
|
|
1248
1287
|
const config = {
|
|
@@ -1252,8 +1291,66 @@ function buildServerConfig(parsed, options = {}) {
|
|
|
1252
1291
|
if (options.env && Object.keys(options.env).length > 0) {
|
|
1253
1292
|
config.env = options.env;
|
|
1254
1293
|
}
|
|
1294
|
+
if (options.autoApproveTools) {
|
|
1295
|
+
config.autoApproveTools = options.autoApproveTools;
|
|
1296
|
+
}
|
|
1255
1297
|
return config;
|
|
1256
1298
|
}
|
|
1299
|
+
function readJsonObject(filePath) {
|
|
1300
|
+
if (!existsSync5(filePath)) {
|
|
1301
|
+
return {};
|
|
1302
|
+
}
|
|
1303
|
+
const parsed = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
1304
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
1305
|
+
}
|
|
1306
|
+
function writeJsonObject(filePath, value) {
|
|
1307
|
+
const dir = dirname6(filePath);
|
|
1308
|
+
if (!existsSync5(dir)) {
|
|
1309
|
+
mkdirSync4(dir, { recursive: true });
|
|
1310
|
+
}
|
|
1311
|
+
writeFileSync4(filePath, `${JSON.stringify(value, null, 2)}
|
|
1312
|
+
`, "utf-8");
|
|
1313
|
+
}
|
|
1314
|
+
function addUniqueStrings(existing, additions) {
|
|
1315
|
+
const values = Array.isArray(existing) ? existing.filter((value) => typeof value === "string") : [];
|
|
1316
|
+
for (const addition of additions) {
|
|
1317
|
+
if (!values.includes(addition)) {
|
|
1318
|
+
values.push(addition);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
return values;
|
|
1322
|
+
}
|
|
1323
|
+
function claudeAutoApproveRules(serverName, tools) {
|
|
1324
|
+
if (tools.length === 0) {
|
|
1325
|
+
return [`mcp__${serverName}`];
|
|
1326
|
+
}
|
|
1327
|
+
return tools.map((tool) => `mcp__${serverName}__${tool}`);
|
|
1328
|
+
}
|
|
1329
|
+
function getClaudeCodeSettingsPath(options = {}) {
|
|
1330
|
+
const local = Boolean(options.local);
|
|
1331
|
+
const cwd = options.cwd || process.cwd();
|
|
1332
|
+
return local ? join3(cwd, ".claude", "settings.local.json") : join3(home2, ".claude", "settings.json");
|
|
1333
|
+
}
|
|
1334
|
+
function installClaudeCodeAutoApproval(serverName, tools, options = {}) {
|
|
1335
|
+
const settingsPath = getClaudeCodeSettingsPath(options);
|
|
1336
|
+
try {
|
|
1337
|
+
const settings = readJsonObject(settingsPath);
|
|
1338
|
+
const permissions = settings.permissions && typeof settings.permissions === "object" && !Array.isArray(settings.permissions) ? settings.permissions : {};
|
|
1339
|
+
permissions.allow = addUniqueStrings(
|
|
1340
|
+
permissions.allow,
|
|
1341
|
+
claudeAutoApproveRules(serverName, tools)
|
|
1342
|
+
);
|
|
1343
|
+
settings.permissions = permissions;
|
|
1344
|
+
writeJsonObject(settingsPath, settings);
|
|
1345
|
+
return { success: true, path: settingsPath };
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
return {
|
|
1348
|
+
success: false,
|
|
1349
|
+
path: settingsPath,
|
|
1350
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1257
1354
|
function updateGitignoreWithPaths(paths, options = {}) {
|
|
1258
1355
|
const cwd = options.cwd || process.cwd();
|
|
1259
1356
|
const gitignorePath = join3(cwd, ".gitignore");
|
|
@@ -1324,10 +1421,27 @@ function installServerForAgent(serverName, serverConfig, agentType, options = {}
|
|
|
1324
1421
|
const configKey = getConfigKey(agent, options);
|
|
1325
1422
|
const config = buildConfigWithKey(configKey, serverName, transformedConfig);
|
|
1326
1423
|
writeConfig2(configPath, config, agent.format, configKey);
|
|
1424
|
+
const extraPaths = [];
|
|
1425
|
+
if (agentType === "claude-code" && gatedConfig.autoApproveTools) {
|
|
1426
|
+
const approval = installClaudeCodeAutoApproval(
|
|
1427
|
+
serverName,
|
|
1428
|
+
gatedConfig.autoApproveTools,
|
|
1429
|
+
options
|
|
1430
|
+
);
|
|
1431
|
+
if (!approval.success) {
|
|
1432
|
+
return {
|
|
1433
|
+
success: false,
|
|
1434
|
+
path: approval.path,
|
|
1435
|
+
error: approval.error
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
extraPaths.push(approval.path);
|
|
1439
|
+
}
|
|
1327
1440
|
return {
|
|
1328
1441
|
success: true,
|
|
1329
1442
|
path: configPath,
|
|
1330
|
-
...dropped.length > 0 ? { droppedFields: dropped } : {}
|
|
1443
|
+
...dropped.length > 0 ? { droppedFields: dropped } : {},
|
|
1444
|
+
...extraPaths.length > 0 ? { extraPaths } : {}
|
|
1331
1445
|
};
|
|
1332
1446
|
} catch (error) {
|
|
1333
1447
|
return {
|
|
@@ -1480,6 +1594,7 @@ export {
|
|
|
1480
1594
|
agents,
|
|
1481
1595
|
getAgentTypes,
|
|
1482
1596
|
supportsProjectConfig,
|
|
1597
|
+
getCommonInstallScopes,
|
|
1483
1598
|
getProjectCapableAgents,
|
|
1484
1599
|
detectProjectAgents,
|
|
1485
1600
|
detectGlobalAgents,
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
detectProjectAgents,
|
|
9
9
|
findMatchingServers,
|
|
10
10
|
getAgentTypes,
|
|
11
|
+
getCommonInstallScopes,
|
|
11
12
|
getConfigPath,
|
|
12
13
|
getFindRegistries,
|
|
13
14
|
getLastSelectedAgents,
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
selectAgentsInteractive,
|
|
24
25
|
supportsProjectConfig,
|
|
25
26
|
updateGitignoreWithPaths
|
|
26
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-3ZFFEEQJ.js";
|
|
27
28
|
|
|
28
29
|
// src/index.ts
|
|
29
30
|
import { program } from "commander";
|
|
@@ -783,7 +784,7 @@ async function runFind(query, options) {
|
|
|
783
784
|
// package.json
|
|
784
785
|
var package_default = {
|
|
785
786
|
name: "add-mcp",
|
|
786
|
-
version: "1.
|
|
787
|
+
version: "1.13.0",
|
|
787
788
|
description: "Add MCP servers to your favorite coding agents with a single command.",
|
|
788
789
|
author: "Andre Landgraf <andre@neon.tech>",
|
|
789
790
|
license: "Apache-2.0",
|
|
@@ -974,6 +975,25 @@ function extractSubcommandOptionsFromArgv() {
|
|
|
974
975
|
result.gitignore = true;
|
|
975
976
|
continue;
|
|
976
977
|
}
|
|
978
|
+
if (arg === "--auto-approve") {
|
|
979
|
+
result.autoApprove = true;
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
if (arg === "--approve-tool") {
|
|
983
|
+
const tools = result.approveTool ? [...result.approveTool] : [];
|
|
984
|
+
let j = i + 1;
|
|
985
|
+
while (j < argv.length) {
|
|
986
|
+
const value = argv[j];
|
|
987
|
+
if (!value || value.startsWith("-")) break;
|
|
988
|
+
tools.push(value);
|
|
989
|
+
j += 1;
|
|
990
|
+
}
|
|
991
|
+
if (tools.length > 0) {
|
|
992
|
+
result.approveTool = tools;
|
|
993
|
+
}
|
|
994
|
+
i = j - 1;
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
977
997
|
if ((arg === "-h" || arg === "--header") && argv[i + 1]) {
|
|
978
998
|
const headers = result.header ? [...result.header] : [];
|
|
979
999
|
headers.push(argv[i + 1]);
|
|
@@ -1126,7 +1146,15 @@ program.name("add-mcp").description(
|
|
|
1126
1146
|
).option(
|
|
1127
1147
|
"--scopes <scopes>",
|
|
1128
1148
|
"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."
|
|
1129
|
-
).option("--oauth-scopes <scopes>", "Alias for --scopes").option(
|
|
1149
|
+
).option("--oauth-scopes <scopes>", "Alias for --scopes").option(
|
|
1150
|
+
"--auto-approve",
|
|
1151
|
+
"Auto-approve MCP tool calls for agents that support it (Codex, Claude Code). Dropped with a warning for other agents."
|
|
1152
|
+
).option(
|
|
1153
|
+
"--approve-tool <tool>",
|
|
1154
|
+
"Tool name to auto-approve when --auto-approve is set (repeatable; defaults to all tools)",
|
|
1155
|
+
collect,
|
|
1156
|
+
[]
|
|
1157
|
+
).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) => {
|
|
1130
1158
|
await main(target, options);
|
|
1131
1159
|
});
|
|
1132
1160
|
program.command("list-agents").description("List all supported coding agents").action(() => {
|
|
@@ -1172,7 +1200,15 @@ program.command("find [keyword]").description(
|
|
|
1172
1200
|
).option("-a, --agent <agent>", "Specify agents to install to", collect, []).option(
|
|
1173
1201
|
"-n, --name <name>",
|
|
1174
1202
|
"Server name override (defaults to catalog entry name)"
|
|
1175
|
-
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1203
|
+
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1204
|
+
"--auto-approve",
|
|
1205
|
+
"Auto-approve MCP tool calls for agents that support it (Codex, Claude Code)"
|
|
1206
|
+
).option(
|
|
1207
|
+
"--approve-tool <tool>",
|
|
1208
|
+
"Tool name to auto-approve when --auto-approve is set (repeatable; defaults to all tools)",
|
|
1209
|
+
collect,
|
|
1210
|
+
[]
|
|
1211
|
+
).option("--all", "Install to all agents").option("--gitignore", "Add generated project config files to .gitignore").action(
|
|
1176
1212
|
async (keyword, options) => {
|
|
1177
1213
|
await runFindCommand(keyword, options);
|
|
1178
1214
|
}
|
|
@@ -1183,7 +1219,15 @@ program.command("search [keyword]").description("Alias for find").option(
|
|
|
1183
1219
|
).option("-a, --agent <agent>", "Specify agents to install to", collect, []).option(
|
|
1184
1220
|
"-n, --name <name>",
|
|
1185
1221
|
"Server name override (defaults to catalog entry name)"
|
|
1186
|
-
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1222
|
+
).option("-y, --yes", "Skip confirmation prompts").option(
|
|
1223
|
+
"--auto-approve",
|
|
1224
|
+
"Auto-approve MCP tool calls for agents that support it (Codex, Claude Code)"
|
|
1225
|
+
).option(
|
|
1226
|
+
"--approve-tool <tool>",
|
|
1227
|
+
"Tool name to auto-approve when --auto-approve is set (repeatable; defaults to all tools)",
|
|
1228
|
+
collect,
|
|
1229
|
+
[]
|
|
1230
|
+
).option("--all", "Install to all agents").option("--gitignore", "Add generated project config files to .gitignore").action(
|
|
1187
1231
|
async (keyword, options) => {
|
|
1188
1232
|
await runFindCommand(keyword, options);
|
|
1189
1233
|
}
|
|
@@ -1829,18 +1873,19 @@ async function main(target, options) {
|
|
|
1829
1873
|
p2.log.warn("--scopes is only used for remote URLs, ignoring");
|
|
1830
1874
|
}
|
|
1831
1875
|
}
|
|
1876
|
+
const approveTools = [...new Set(options.approveTool ?? [])];
|
|
1877
|
+
const autoApproveTools = options.autoApprove || approveTools.length > 0 ? approveTools : void 0;
|
|
1832
1878
|
const serverConfig = buildServerConfig(parsed, {
|
|
1833
1879
|
transport: resolvedTransport,
|
|
1834
1880
|
headers: headersForConfig && Object.keys(headersForConfig).length > 0 ? headersForConfig : void 0,
|
|
1835
1881
|
env: envForConfig && Object.keys(envForConfig).length > 0 ? envForConfig : void 0,
|
|
1836
1882
|
args: argsForConfig && argsForConfig.length > 0 ? argsForConfig : void 0,
|
|
1837
1883
|
timeout: resolvedTimeout,
|
|
1838
|
-
oauthScopes: resolvedScopes
|
|
1884
|
+
oauthScopes: resolvedScopes,
|
|
1885
|
+
autoApproveTools
|
|
1839
1886
|
});
|
|
1840
1887
|
let targetAgents;
|
|
1841
1888
|
const allAgentTypes = getAgentTypes();
|
|
1842
|
-
const hasExplicitAgentFlags = options.agent && options.agent.length > 0 || options.all === true;
|
|
1843
|
-
let selectedViaPrompt = false;
|
|
1844
1889
|
let agentRouting = /* @__PURE__ */ new Map();
|
|
1845
1890
|
if (options.agent && options.agent.length > 0) {
|
|
1846
1891
|
const resolved = [];
|
|
@@ -1900,7 +1945,7 @@ async function main(target, options) {
|
|
|
1900
1945
|
);
|
|
1901
1946
|
}
|
|
1902
1947
|
} else {
|
|
1903
|
-
const availableAgents =
|
|
1948
|
+
const availableAgents = allAgentTypes;
|
|
1904
1949
|
p2.log.warn(
|
|
1905
1950
|
options.global ? "No coding agents detected." : "No agents detected in this project."
|
|
1906
1951
|
);
|
|
@@ -1911,18 +1956,14 @@ async function main(target, options) {
|
|
|
1911
1956
|
p2.cancel("Installation cancelled");
|
|
1912
1957
|
process.exit(0);
|
|
1913
1958
|
}
|
|
1914
|
-
selectedViaPrompt = true;
|
|
1915
1959
|
targetAgents = selected;
|
|
1916
|
-
for (const agent of targetAgents) {
|
|
1917
|
-
agentRouting.set(agent, options.global ? "global" : "local");
|
|
1918
|
-
}
|
|
1919
1960
|
}
|
|
1920
1961
|
} else if (options.yes) {
|
|
1921
1962
|
targetAgents = detectedAgents;
|
|
1922
1963
|
const agentNames = detectedAgents.map((a) => chalk.cyan(agents[a].displayName)).join(", ");
|
|
1923
1964
|
p2.log.info(`Installing to: ${agentNames}`);
|
|
1924
1965
|
} else {
|
|
1925
|
-
const availableAgents =
|
|
1966
|
+
const availableAgents = allAgentTypes;
|
|
1926
1967
|
let lastSelected;
|
|
1927
1968
|
try {
|
|
1928
1969
|
lastSelected = await getLastSelectedAgents();
|
|
@@ -1944,11 +1985,7 @@ async function main(target, options) {
|
|
|
1944
1985
|
p2.cancel("Installation cancelled");
|
|
1945
1986
|
process.exit(0);
|
|
1946
1987
|
}
|
|
1947
|
-
selectedViaPrompt = true;
|
|
1948
1988
|
targetAgents = selected;
|
|
1949
|
-
for (const agent of targetAgents) {
|
|
1950
|
-
agentRouting.set(agent, options.global ? "global" : "local");
|
|
1951
|
-
}
|
|
1952
1989
|
}
|
|
1953
1990
|
}
|
|
1954
1991
|
const requiredTransport = isRemoteSource(parsed) ? resolvedTransport ?? "http" : "stdio";
|
|
@@ -1982,70 +2019,62 @@ async function main(target, options) {
|
|
|
1982
2019
|
process.exit(1);
|
|
1983
2020
|
}
|
|
1984
2021
|
}
|
|
1985
|
-
const hasSmartRouting = agentRouting.size > 0;
|
|
1986
2022
|
if (options.global) {
|
|
2023
|
+
agentRouting = /* @__PURE__ */ new Map();
|
|
1987
2024
|
for (const agent of targetAgents) {
|
|
1988
2025
|
agentRouting.set(agent, "global");
|
|
1989
2026
|
}
|
|
1990
|
-
} else
|
|
1991
|
-
const
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
(a) => !supportsProjectConfig(a)
|
|
1996
|
-
);
|
|
1997
|
-
for (const agent of globalOnlySelected) {
|
|
1998
|
-
agentRouting.set(agent, "global");
|
|
2027
|
+
} else {
|
|
2028
|
+
const commonScopes = getCommonInstallScopes(targetAgents);
|
|
2029
|
+
if (commonScopes.length === 0) {
|
|
2030
|
+
p2.log.error("No agents selected");
|
|
2031
|
+
process.exit(1);
|
|
1999
2032
|
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
process.exit(0);
|
|
2021
|
-
}
|
|
2022
|
-
installLocally = scope;
|
|
2023
|
-
}
|
|
2024
|
-
for (const agent of selectedWithLocal) {
|
|
2025
|
-
agentRouting.set(agent, installLocally ? "local" : "global");
|
|
2033
|
+
let installScope = commonScopes[0];
|
|
2034
|
+
if (commonScopes.length > 1 && !options.yes) {
|
|
2035
|
+
const scope = await p2.select({
|
|
2036
|
+
message: "Installation scope",
|
|
2037
|
+
options: [
|
|
2038
|
+
{
|
|
2039
|
+
value: "local",
|
|
2040
|
+
label: "Project",
|
|
2041
|
+
hint: "Install in current directory (committed with your project)"
|
|
2042
|
+
},
|
|
2043
|
+
{
|
|
2044
|
+
value: "global",
|
|
2045
|
+
label: "Global",
|
|
2046
|
+
hint: "Install in home directory (available across all projects)"
|
|
2047
|
+
}
|
|
2048
|
+
]
|
|
2049
|
+
});
|
|
2050
|
+
if (p2.isCancel(scope)) {
|
|
2051
|
+
p2.cancel("Installation cancelled");
|
|
2052
|
+
process.exit(0);
|
|
2026
2053
|
}
|
|
2027
|
-
|
|
2028
|
-
|
|
2054
|
+
installScope = scope;
|
|
2055
|
+
} else if (installScope === "global") {
|
|
2056
|
+
p2.log.info("Selected agents require global installation");
|
|
2057
|
+
}
|
|
2058
|
+
agentRouting = /* @__PURE__ */ new Map();
|
|
2059
|
+
for (const agent of targetAgents) {
|
|
2060
|
+
agentRouting.set(agent, installScope);
|
|
2029
2061
|
}
|
|
2030
2062
|
}
|
|
2031
2063
|
const summaryLines = [];
|
|
2032
2064
|
summaryLines.push(`${chalk.cyan("Server:")} ${serverName}`);
|
|
2033
2065
|
summaryLines.push(`${chalk.cyan("Type:")} ${sourceType}`);
|
|
2066
|
+
if (autoApproveTools) {
|
|
2067
|
+
summaryLines.push(
|
|
2068
|
+
`${chalk.cyan("Auto-approve:")} ${autoApproveTools.length === 0 ? "All tools" : autoApproveTools.join(", ")}`
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2034
2071
|
const localAgents = targetAgents.filter(
|
|
2035
2072
|
(a) => agentRouting.get(a) === "local"
|
|
2036
2073
|
);
|
|
2037
2074
|
const globalAgents = targetAgents.filter(
|
|
2038
2075
|
(a) => agentRouting.get(a) === "global"
|
|
2039
2076
|
);
|
|
2040
|
-
if (localAgents.length > 0
|
|
2041
|
-
summaryLines.push(`${chalk.cyan("Scope:")} Mixed (project + global)`);
|
|
2042
|
-
summaryLines.push(
|
|
2043
|
-
`${chalk.cyan(" Project:")} ${localAgents.map((a) => agents[a].displayName).join(", ")}`
|
|
2044
|
-
);
|
|
2045
|
-
summaryLines.push(
|
|
2046
|
-
`${chalk.cyan(" Global:")} ${globalAgents.map((a) => agents[a].displayName).join(", ")}`
|
|
2047
|
-
);
|
|
2048
|
-
} else if (localAgents.length > 0) {
|
|
2077
|
+
if (localAgents.length > 0) {
|
|
2049
2078
|
summaryLines.push(`${chalk.cyan("Scope:")} Project`);
|
|
2050
2079
|
summaryLines.push(
|
|
2051
2080
|
`${chalk.cyan("Agents:")} ${localAgents.map((a) => agents[a].displayName).join(", ")}`
|
|
@@ -2083,6 +2112,11 @@ async function main(target, options) {
|
|
|
2083
2112
|
resultLines.push(
|
|
2084
2113
|
`${chalk.green("\u2713")} ${agent.displayName}: ${chalk.dim(shortPath)}`
|
|
2085
2114
|
);
|
|
2115
|
+
for (const extraPath of result.extraPaths ?? []) {
|
|
2116
|
+
resultLines.push(
|
|
2117
|
+
` ${chalk.dim("\u21B3 permissions:")} ${chalk.dim(shortenPath(extraPath))}`
|
|
2118
|
+
);
|
|
2119
|
+
}
|
|
2086
2120
|
}
|
|
2087
2121
|
p2.note(
|
|
2088
2122
|
resultLines.join("\n"),
|
|
@@ -2118,12 +2152,15 @@ async function main(target, options) {
|
|
|
2118
2152
|
`${describeOptionalField(field)} is not supported by ${agentNames.join(", ")}; dropped from ${agentNames.length === 1 ? "that config" : "those configs"}.`
|
|
2119
2153
|
);
|
|
2120
2154
|
}
|
|
2121
|
-
if (options.gitignore &&
|
|
2155
|
+
if (options.gitignore && localAgents.length === 0) {
|
|
2122
2156
|
p2.log.warn(
|
|
2123
2157
|
"--gitignore is only supported for project-scoped installations; ignoring."
|
|
2124
2158
|
);
|
|
2125
2159
|
} else if (options.gitignore) {
|
|
2126
|
-
const successfulPaths = successful.
|
|
2160
|
+
const successfulPaths = successful.flatMap(([_, result]) => [
|
|
2161
|
+
result.path,
|
|
2162
|
+
...result.extraPaths ?? []
|
|
2163
|
+
]);
|
|
2127
2164
|
const gitignoreUpdate = updateGitignoreWithPaths(successfulPaths);
|
|
2128
2165
|
if (gitignoreUpdate.added.length > 0) {
|
|
2129
2166
|
p2.log.info(
|
package/dist/lib.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* before its transform runs, guaranteeing that only known fields are ever
|
|
9
9
|
* written to a client config.
|
|
10
10
|
*/
|
|
11
|
-
type OptionalField = "timeout" | "scopes";
|
|
11
|
+
type OptionalField = "timeout" | "scopes" | "autoApprove";
|
|
12
12
|
|
|
13
13
|
type AgentType = "antigravity" | "cline" | "cline-cli" | "claude-code" | "claude-desktop" | "codex" | "cursor" | "gemini-cli" | "goose" | "github-copilot-cli" | "mcporter" | "opencode" | "vscode" | "windsurf" | "zed";
|
|
14
14
|
type ConfigFormat = "json" | "yaml" | "toml";
|
|
@@ -79,6 +79,15 @@ interface McpServerConfig {
|
|
|
79
79
|
* their own native shape (e.g. Cursor `auth.scopes`, Gemini `oauth.scopes`).
|
|
80
80
|
*/
|
|
81
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[];
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
interface InstallOptions {
|
|
@@ -96,6 +105,12 @@ interface InstallResult {
|
|
|
96
105
|
* does not support them. Empty/undefined when nothing was dropped.
|
|
97
106
|
*/
|
|
98
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[];
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
declare const agents: Record<AgentType, AgentConfig>;
|
package/dist/lib.js
CHANGED