metheus-governance-mcp-cli 0.2.26 → 0.2.29
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 +7 -2
- package/cli.mjs +256 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctx
|
|
|
48
48
|
|
|
49
49
|
Gemini CLI note:
|
|
50
50
|
- `gemini mcp` commands require Gemini auth to be configured first (`GEMINI_API_KEY` or `~/.gemini/settings.json` auth).
|
|
51
|
+
- `setup` registers Gemini in both `user` and `project` scopes to improve auto-discovery across folders.
|
|
51
52
|
|
|
52
53
|
When a client does not send workspace metadata (for example some Codex sessions),
|
|
53
54
|
set a stable fallback root once:
|
|
@@ -58,7 +59,7 @@ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctx
|
|
|
58
59
|
|
|
59
60
|
This sets fallback workspace context for clients that do not pass workspace metadata:
|
|
60
61
|
- Codex/Antigravity/Cursor: `METHEUS_WORKSPACE_DIR` env
|
|
61
|
-
- Gemini: pinned `--workspace-dir <fallback>` in
|
|
62
|
+
- Gemini: pinned `--workspace-dir <fallback>` and `METHEUS_WORKSPACE_DIR` in MCP registration
|
|
62
63
|
|
|
63
64
|
Guardrail note:
|
|
64
65
|
- By default, CLI blocks reading/writing ctxpack sync metadata when workspace root resolves to the home directory.
|
|
@@ -92,7 +93,11 @@ Checks:
|
|
|
92
93
|
`setup` auto-registers this server for `codex`, `claude`, `gemini`, `antigravity`, and `cursor` when those CLIs are available.
|
|
93
94
|
|
|
94
95
|
Antigravity note:
|
|
95
|
-
- this CLI manages MCP registration via Antigravity local config
|
|
96
|
+
- this CLI manages MCP registration via Antigravity local config because Antigravity does not provide full `mcp list/get/remove` subcommands.
|
|
97
|
+
- primary config path: `~/.gemini/antigravity/mcp_config.json`
|
|
98
|
+
- legacy mirror path: `%APPDATA%/Antigravity/User/mcp.json` (Windows) for compatibility
|
|
99
|
+
- for compatibility across Antigravity variants, setup writes both `mcpServers` and `servers` keys.
|
|
100
|
+
- proxy stdio now supports both `Content-Length` framed MCP and JSONL input for VS Code-family clients.
|
|
96
101
|
|
|
97
102
|
Cursor note:
|
|
98
103
|
- this CLI manages MCP registration via Cursor global MCP config (`~/.cursor/mcp.json`).
|
package/cli.mjs
CHANGED
|
@@ -86,7 +86,15 @@ function resolveHomeFilePath(relativePath) {
|
|
|
86
86
|
return path.join(home, relativePath);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
function
|
|
89
|
+
function antigravityPrimaryMcpConfigFilePath() {
|
|
90
|
+
const home = String(process.env.USERPROFILE || process.env.HOME || "").trim();
|
|
91
|
+
if (home) {
|
|
92
|
+
return path.join(home, ".gemini", "antigravity", "mcp_config.json");
|
|
93
|
+
}
|
|
94
|
+
return path.resolve(process.cwd(), ".gemini", "antigravity", "mcp_config.json");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function antigravityLegacyMcpConfigFilePath() {
|
|
90
98
|
const home = String(process.env.USERPROFILE || process.env.HOME || "").trim();
|
|
91
99
|
if (process.platform === "win32") {
|
|
92
100
|
const appData = String(process.env.APPDATA || "").trim();
|
|
@@ -110,44 +118,117 @@ function antigravityMcpConfigFilePath() {
|
|
|
110
118
|
return path.resolve(process.cwd(), ".antigravity", "mcp.json");
|
|
111
119
|
}
|
|
112
120
|
|
|
121
|
+
function antigravityMcpConfigFilePaths() {
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
const out = [];
|
|
124
|
+
const pushUnique = (value) => {
|
|
125
|
+
const normalized = String(value || "").trim();
|
|
126
|
+
if (!normalized || seen.has(normalized)) return;
|
|
127
|
+
seen.add(normalized);
|
|
128
|
+
out.push(normalized);
|
|
129
|
+
};
|
|
130
|
+
pushUnique(antigravityPrimaryMcpConfigFilePath());
|
|
131
|
+
pushUnique(antigravityLegacyMcpConfigFilePath());
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
|
|
113
135
|
function loadAntigravityMcpConfig() {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
136
|
+
const candidatePaths = antigravityMcpConfigFilePaths();
|
|
137
|
+
for (const filePath of candidatePaths) {
|
|
138
|
+
try {
|
|
139
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
140
|
+
const parsed = tryJsonParse(raw);
|
|
141
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
142
|
+
return { filePath, config: parsed };
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
// no-op
|
|
120
146
|
}
|
|
121
|
-
} catch {
|
|
122
|
-
// no-op
|
|
123
147
|
}
|
|
124
148
|
return {
|
|
125
|
-
filePath,
|
|
149
|
+
filePath: candidatePaths[0] || antigravityPrimaryMcpConfigFilePath(),
|
|
126
150
|
config: {
|
|
151
|
+
mcpServers: {},
|
|
127
152
|
servers: {},
|
|
128
|
-
inputs: [],
|
|
129
153
|
},
|
|
130
154
|
};
|
|
131
155
|
}
|
|
132
156
|
|
|
133
157
|
function saveAntigravityMcpConfig(filePath, config) {
|
|
158
|
+
const primaryPath = String(filePath || "").trim();
|
|
159
|
+
if (!primaryPath) return false;
|
|
160
|
+
const mirrorPaths = antigravityMcpConfigFilePaths().filter((item) => item !== primaryPath);
|
|
134
161
|
try {
|
|
135
|
-
fs.mkdirSync(path.dirname(
|
|
136
|
-
fs.writeFileSync(
|
|
137
|
-
return true;
|
|
162
|
+
fs.mkdirSync(path.dirname(primaryPath), { recursive: true });
|
|
163
|
+
fs.writeFileSync(primaryPath, `${JSON.stringify(config, null, "\t")}\n`, "utf8");
|
|
138
164
|
} catch {
|
|
139
165
|
return false;
|
|
140
166
|
}
|
|
167
|
+
for (const extraPath of mirrorPaths) {
|
|
168
|
+
try {
|
|
169
|
+
fs.mkdirSync(path.dirname(extraPath), { recursive: true });
|
|
170
|
+
fs.writeFileSync(extraPath, `${JSON.stringify(config, null, "\t")}\n`, "utf8");
|
|
171
|
+
} catch {
|
|
172
|
+
// best effort mirror for compatibility
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
141
176
|
}
|
|
142
177
|
|
|
143
178
|
function getAntigravityServerEntry(serverName) {
|
|
144
179
|
const { config } = loadAntigravityMcpConfig();
|
|
145
|
-
const servers = safeObject(config?.servers);
|
|
180
|
+
const servers = safeObject(config?.mcpServers ?? config?.servers);
|
|
181
|
+
const entry = safeObject(servers[serverName]);
|
|
182
|
+
if (!entry.command && !entry.url) return null;
|
|
183
|
+
return entry;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function geminiSettingsFilePath(scope = "project") {
|
|
187
|
+
const normalized = String(scope || "project").trim().toLowerCase();
|
|
188
|
+
if (normalized === "user") {
|
|
189
|
+
const home = String(process.env.USERPROFILE || process.env.HOME || "").trim();
|
|
190
|
+
if (home) {
|
|
191
|
+
return path.join(home, ".gemini", "settings.json");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return path.resolve(process.cwd(), ".gemini", "settings.json");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function loadGeminiSettings(scope = "project") {
|
|
198
|
+
const filePath = geminiSettingsFilePath(scope);
|
|
199
|
+
try {
|
|
200
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
201
|
+
const parsed = tryJsonParse(raw);
|
|
202
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
203
|
+
return { filePath, config: parsed };
|
|
204
|
+
}
|
|
205
|
+
} catch {
|
|
206
|
+
// no-op
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
filePath,
|
|
210
|
+
config: {
|
|
211
|
+
mcpServers: {},
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function getGeminiServerEntryByScope(serverName, scope = "project") {
|
|
217
|
+
const { config } = loadGeminiSettings(scope);
|
|
218
|
+
const servers = safeObject(config?.mcpServers);
|
|
146
219
|
const entry = safeObject(servers[serverName]);
|
|
147
220
|
if (!entry.command && !entry.url) return null;
|
|
148
221
|
return entry;
|
|
149
222
|
}
|
|
150
223
|
|
|
224
|
+
function getGeminiServerEntry(serverName) {
|
|
225
|
+
return (
|
|
226
|
+
getGeminiServerEntryByScope(serverName, "project")
|
|
227
|
+
|| getGeminiServerEntryByScope(serverName, "user")
|
|
228
|
+
|| null
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
151
232
|
function cursorMcpConfigFilePath() {
|
|
152
233
|
const home = String(process.env.USERPROFILE || process.env.HOME || "").trim();
|
|
153
234
|
if (home) {
|
|
@@ -3898,12 +3979,7 @@ async function runProxy(flags) {
|
|
|
3898
3979
|
let sessionWorkspaceDir = "";
|
|
3899
3980
|
let sessionWorkspaceTrusted = false;
|
|
3900
3981
|
|
|
3901
|
-
const
|
|
3902
|
-
input: process.stdin,
|
|
3903
|
-
crlfDelay: Infinity,
|
|
3904
|
-
});
|
|
3905
|
-
|
|
3906
|
-
rl.on("line", async (lineRaw) => {
|
|
3982
|
+
const handleIncomingMessage = async (lineRaw) => {
|
|
3907
3983
|
const line = String(lineRaw || "").trim();
|
|
3908
3984
|
if (!line) return;
|
|
3909
3985
|
|
|
@@ -4234,7 +4310,137 @@ async function runProxy(flags) {
|
|
|
4234
4310
|
`${JSON.stringify(jsonRpcError(requestObj, -32001, String(err?.message || err)))}\n`,
|
|
4235
4311
|
);
|
|
4236
4312
|
}
|
|
4313
|
+
};
|
|
4314
|
+
|
|
4315
|
+
let pendingInputBuffer = Buffer.alloc(0);
|
|
4316
|
+
let messageQueue = Promise.resolve();
|
|
4317
|
+
|
|
4318
|
+
function queueMessage(messageText) {
|
|
4319
|
+
const nextText = String(messageText || "");
|
|
4320
|
+
if (!nextText.trim()) return;
|
|
4321
|
+
messageQueue = messageQueue
|
|
4322
|
+
.then(() => handleIncomingMessage(nextText))
|
|
4323
|
+
.catch((err) => {
|
|
4324
|
+
process.stderr.write(`${String(err?.stack || err)}\n`);
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4327
|
+
|
|
4328
|
+
function indexOfBuffer(haystack, needle) {
|
|
4329
|
+
return haystack.indexOf(needle);
|
|
4330
|
+
}
|
|
4331
|
+
|
|
4332
|
+
function startsWithContentLengthHeader(buffer) {
|
|
4333
|
+
if (!Buffer.isBuffer(buffer) || buffer.length === 0) return false;
|
|
4334
|
+
let start = 0;
|
|
4335
|
+
while (start < buffer.length && (buffer[start] === 0x0d || buffer[start] === 0x0a)) {
|
|
4336
|
+
start += 1;
|
|
4337
|
+
}
|
|
4338
|
+
const previewLength = Math.min(96, buffer.length - start);
|
|
4339
|
+
if (previewLength <= 0) return false;
|
|
4340
|
+
const preview = buffer.subarray(start, start + previewLength).toString("utf8");
|
|
4341
|
+
return /^\s*content-length\s*:/i.test(preview);
|
|
4342
|
+
}
|
|
4343
|
+
|
|
4344
|
+
function extractFramedMessage(buffer) {
|
|
4345
|
+
const crlfDelimiter = Buffer.from("\r\n\r\n");
|
|
4346
|
+
const lfDelimiter = Buffer.from("\n\n");
|
|
4347
|
+
let headerEnd = indexOfBuffer(buffer, crlfDelimiter);
|
|
4348
|
+
let delimiterLength = crlfDelimiter.length;
|
|
4349
|
+
if (headerEnd < 0) {
|
|
4350
|
+
headerEnd = indexOfBuffer(buffer, lfDelimiter);
|
|
4351
|
+
delimiterLength = lfDelimiter.length;
|
|
4352
|
+
}
|
|
4353
|
+
if (headerEnd < 0) return null;
|
|
4354
|
+
|
|
4355
|
+
const headerText = buffer.subarray(0, headerEnd).toString("utf8");
|
|
4356
|
+
const match = /content-length\s*:\s*(\d+)/i.exec(headerText);
|
|
4357
|
+
if (!match) {
|
|
4358
|
+
// Malformed framed payload; drop header block and continue.
|
|
4359
|
+
return {
|
|
4360
|
+
message: "",
|
|
4361
|
+
remaining: buffer.subarray(headerEnd + delimiterLength),
|
|
4362
|
+
};
|
|
4363
|
+
}
|
|
4364
|
+
|
|
4365
|
+
const bodyLength = Number.parseInt(String(match[1] || "0"), 10);
|
|
4366
|
+
if (!Number.isFinite(bodyLength) || bodyLength < 0) {
|
|
4367
|
+
return {
|
|
4368
|
+
message: "",
|
|
4369
|
+
remaining: buffer.subarray(headerEnd + delimiterLength),
|
|
4370
|
+
};
|
|
4371
|
+
}
|
|
4372
|
+
|
|
4373
|
+
const bodyStart = headerEnd + delimiterLength;
|
|
4374
|
+
const bodyEnd = bodyStart + bodyLength;
|
|
4375
|
+
if (buffer.length < bodyEnd) return null;
|
|
4376
|
+
const message = buffer.subarray(bodyStart, bodyEnd).toString("utf8");
|
|
4377
|
+
return {
|
|
4378
|
+
message,
|
|
4379
|
+
remaining: buffer.subarray(bodyEnd),
|
|
4380
|
+
};
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
function extractLineMessage(buffer) {
|
|
4384
|
+
const newlineIndex = buffer.indexOf(0x0a);
|
|
4385
|
+
if (newlineIndex < 0) return null;
|
|
4386
|
+
let lineBuffer = buffer.subarray(0, newlineIndex);
|
|
4387
|
+
if (lineBuffer.length > 0 && lineBuffer[lineBuffer.length - 1] === 0x0d) {
|
|
4388
|
+
lineBuffer = lineBuffer.subarray(0, lineBuffer.length - 1);
|
|
4389
|
+
}
|
|
4390
|
+
return {
|
|
4391
|
+
message: lineBuffer.toString("utf8"),
|
|
4392
|
+
remaining: buffer.subarray(newlineIndex + 1),
|
|
4393
|
+
};
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
function pumpInputBuffer() {
|
|
4397
|
+
// Supports both MCP framed stdio (Content-Length) and JSONL input.
|
|
4398
|
+
while (pendingInputBuffer.length > 0) {
|
|
4399
|
+
let trimmedLeading = pendingInputBuffer;
|
|
4400
|
+
while (
|
|
4401
|
+
trimmedLeading.length > 0
|
|
4402
|
+
&& (trimmedLeading[0] === 0x0d || trimmedLeading[0] === 0x0a)
|
|
4403
|
+
) {
|
|
4404
|
+
trimmedLeading = trimmedLeading.subarray(1);
|
|
4405
|
+
}
|
|
4406
|
+
pendingInputBuffer = trimmedLeading;
|
|
4407
|
+
if (pendingInputBuffer.length === 0) break;
|
|
4408
|
+
|
|
4409
|
+
if (startsWithContentLengthHeader(pendingInputBuffer)) {
|
|
4410
|
+
const framed = extractFramedMessage(pendingInputBuffer);
|
|
4411
|
+
if (!framed) break;
|
|
4412
|
+
pendingInputBuffer = framed.remaining;
|
|
4413
|
+
if (String(framed.message || "").trim()) {
|
|
4414
|
+
queueMessage(framed.message);
|
|
4415
|
+
}
|
|
4416
|
+
continue;
|
|
4417
|
+
}
|
|
4418
|
+
|
|
4419
|
+
const lineMessage = extractLineMessage(pendingInputBuffer);
|
|
4420
|
+
if (!lineMessage) break;
|
|
4421
|
+
pendingInputBuffer = lineMessage.remaining;
|
|
4422
|
+
if (String(lineMessage.message || "").trim()) {
|
|
4423
|
+
queueMessage(lineMessage.message);
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
|
|
4428
|
+
process.stdin.on("data", (chunk) => {
|
|
4429
|
+
const nextChunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
4430
|
+
pendingInputBuffer = pendingInputBuffer.length
|
|
4431
|
+
? Buffer.concat([pendingInputBuffer, nextChunk])
|
|
4432
|
+
: nextChunk;
|
|
4433
|
+
pumpInputBuffer();
|
|
4434
|
+
});
|
|
4435
|
+
|
|
4436
|
+
process.stdin.on("end", () => {
|
|
4437
|
+
const trailing = String(pendingInputBuffer.toString("utf8") || "").trim();
|
|
4438
|
+
if (trailing) {
|
|
4439
|
+
queueMessage(trailing);
|
|
4440
|
+
}
|
|
4237
4441
|
});
|
|
4442
|
+
|
|
4443
|
+
process.stdin.resume();
|
|
4238
4444
|
}
|
|
4239
4445
|
|
|
4240
4446
|
function runCLICommand(cliBin, args, options = {}) {
|
|
@@ -4306,7 +4512,7 @@ function tryRegister(cliBin, serverName, proxyArgs, options = {}) {
|
|
|
4306
4512
|
if (cliBin === "antigravity") {
|
|
4307
4513
|
const { filePath, config } = loadAntigravityMcpConfig();
|
|
4308
4514
|
const nextConfig = safeObject(config);
|
|
4309
|
-
const nextServers = safeObject(nextConfig.servers);
|
|
4515
|
+
const nextServers = safeObject(nextConfig.mcpServers ?? nextConfig.servers);
|
|
4310
4516
|
const existing = safeObject(nextServers[serverName]);
|
|
4311
4517
|
const args = [selfPath, "proxy", ...proxyArgs];
|
|
4312
4518
|
const entry = {
|
|
@@ -4330,25 +4536,36 @@ function tryRegister(cliBin, serverName, proxyArgs, options = {}) {
|
|
|
4330
4536
|
}
|
|
4331
4537
|
}
|
|
4332
4538
|
nextServers[serverName] = entry;
|
|
4333
|
-
nextConfig.
|
|
4334
|
-
|
|
4335
|
-
nextConfig.inputs = [];
|
|
4336
|
-
}
|
|
4539
|
+
nextConfig.mcpServers = nextServers;
|
|
4540
|
+
nextConfig.servers = { ...nextServers };
|
|
4337
4541
|
return saveAntigravityMcpConfig(filePath, nextConfig);
|
|
4338
4542
|
}
|
|
4339
4543
|
if (cliBin === "gemini") {
|
|
4340
|
-
//
|
|
4341
|
-
// gemini mcp add <name> <commandOrUrl> [args...]
|
|
4342
|
-
// It does not expose --env for MCP registration, so pin workspace-dir directly.
|
|
4544
|
+
// Register in both user+project scopes for broader auto-discovery across folders.
|
|
4343
4545
|
const geminiProxyArgs = workspaceEnv
|
|
4344
4546
|
? withWorkspaceDirArg(proxyArgs, workspaceEnv)
|
|
4345
4547
|
: [...proxyArgs];
|
|
4346
|
-
const
|
|
4548
|
+
const geminiEnvArgs = workspaceEnv
|
|
4549
|
+
? ["-e", `METHEUS_WORKSPACE_DIR=${workspaceEnv}`]
|
|
4550
|
+
: [];
|
|
4551
|
+
const geminiBaseArgs = [serverName, process.execPath, selfPath, "proxy", ...geminiProxyArgs];
|
|
4552
|
+
let ok = false;
|
|
4553
|
+
const scopedAttempts = [
|
|
4554
|
+
["mcp", "add", "-s", "user", ...geminiEnvArgs, ...geminiBaseArgs],
|
|
4555
|
+
["mcp", "add", "-s", "project", ...geminiEnvArgs, ...geminiBaseArgs],
|
|
4556
|
+
];
|
|
4557
|
+
for (const args of scopedAttempts) {
|
|
4558
|
+
const run = runCLICommand(cliBin, args, { stdio: "inherit" });
|
|
4559
|
+
if (run.status === 0) ok = true;
|
|
4560
|
+
}
|
|
4561
|
+
if (ok) return true;
|
|
4562
|
+
// Backward compatibility for older Gemini CLI variants without scope/env flags.
|
|
4563
|
+
const legacyRun = runCLICommand(
|
|
4347
4564
|
cliBin,
|
|
4348
4565
|
["mcp", "add", serverName, process.execPath, selfPath, "proxy", ...geminiProxyArgs],
|
|
4349
4566
|
{ stdio: "inherit" },
|
|
4350
4567
|
);
|
|
4351
|
-
return
|
|
4568
|
+
return legacyRun.status === 0;
|
|
4352
4569
|
}
|
|
4353
4570
|
|
|
4354
4571
|
const baseAddArgs = (() => {
|
|
@@ -4395,13 +4612,11 @@ function runRemove(cliBin, serverName) {
|
|
|
4395
4612
|
if (cliBin === "antigravity") {
|
|
4396
4613
|
const { filePath, config } = loadAntigravityMcpConfig();
|
|
4397
4614
|
const nextConfig = safeObject(config);
|
|
4398
|
-
const nextServers = safeObject(nextConfig.servers);
|
|
4615
|
+
const nextServers = safeObject(nextConfig.mcpServers ?? nextConfig.servers);
|
|
4399
4616
|
if (Object.prototype.hasOwnProperty.call(nextServers, serverName)) {
|
|
4400
4617
|
delete nextServers[serverName];
|
|
4401
|
-
nextConfig.
|
|
4402
|
-
|
|
4403
|
-
nextConfig.inputs = [];
|
|
4404
|
-
}
|
|
4618
|
+
nextConfig.mcpServers = nextServers;
|
|
4619
|
+
nextConfig.servers = { ...nextServers };
|
|
4405
4620
|
saveAntigravityMcpConfig(filePath, nextConfig);
|
|
4406
4621
|
}
|
|
4407
4622
|
return;
|
|
@@ -4416,6 +4631,8 @@ function runRemove(cliBin, serverName) {
|
|
|
4416
4631
|
return;
|
|
4417
4632
|
}
|
|
4418
4633
|
if (cliBin === "gemini") {
|
|
4634
|
+
runCLICommand(cliBin, ["mcp", "remove", "-s", "project", serverName], { stdio: "ignore" });
|
|
4635
|
+
runCLICommand(cliBin, ["mcp", "remove", "-s", "user", serverName], { stdio: "ignore" });
|
|
4419
4636
|
runCLICommand(cliBin, ["mcp", "remove", serverName], { stdio: "ignore" });
|
|
4420
4637
|
return;
|
|
4421
4638
|
}
|
|
@@ -4430,6 +4647,9 @@ function isRegistered(cliBin, serverName) {
|
|
|
4430
4647
|
return Boolean(getAntigravityServerEntry(serverName));
|
|
4431
4648
|
}
|
|
4432
4649
|
if (cliBin === "gemini") {
|
|
4650
|
+
if (getGeminiServerEntry(serverName)) {
|
|
4651
|
+
return true;
|
|
4652
|
+
}
|
|
4433
4653
|
const listRun = runCLICommand(cliBin, ["mcp", "list"], { stdio: "pipe" });
|
|
4434
4654
|
if (listRun.status !== 0) return false;
|
|
4435
4655
|
const text = `${String(listRun.stdout || "")}\n${String(listRun.stderr || "")}`;
|