feat(admin): apply MCP allowlist to extensions & gemini mcp list command (#18442)

This commit is contained in:
Shreya Keshive
2026-02-06 13:07:00 -05:00
committed by GitHub
parent 5f4fa08b38
commit 197dfed757
12 changed files with 400 additions and 58 deletions

View File

@@ -1511,7 +1511,7 @@ describe('loadCliConfig with admin.mcp.config', () => {
});
const config = await loadCliConfig(settings, 'test-session', argv);
const mergedServers = config.getMcpServers();
const mergedServers = config.getMcpServers() ?? {};
expect(mergedServers).toHaveProperty('serverA');
expect(mergedServers).not.toHaveProperty('serverB');
});
@@ -1569,9 +1569,9 @@ describe('loadCliConfig with admin.mcp.config', () => {
});
const config = await loadCliConfig(settings, 'test-session', argv);
const mergedServers = config.getMcpServers();
const mergedServers = config.getMcpServers() ?? {};
expect(mergedServers).not.toHaveProperty('serverC');
expect(Object.keys(mergedServers || {})).toHaveLength(0);
expect(Object.keys(mergedServers)).toHaveLength(0);
});
it('should merge local fields and prefer admin tool filters', async () => {
@@ -1601,7 +1601,7 @@ describe('loadCliConfig with admin.mcp.config', () => {
});
const config = await loadCliConfig(settings, 'test-session', argv);
const serverA = config.getMcpServers()?.['serverA'];
const serverA = (config.getMcpServers() ?? {})['serverA'];
expect(serverA).toMatchObject({
timeout: 1234,
includeTools: ['admin_tool'],

View File

@@ -36,9 +36,10 @@ import {
GEMINI_MODEL_ALIAS_AUTO,
getAdminErrorMessage,
Config,
applyAdminAllowlist,
getAdminBlockedMcpServersMessage,
} from '@google/gemini-cli-core';
import type {
MCPServerConfig,
HookDefinition,
HookEventName,
OutputFormat,
@@ -692,38 +693,17 @@ export async function loadCliConfig(
let mcpServers = mcpEnabled ? settings.mcpServers : {};
if (mcpEnabled && adminAllowlist && Object.keys(adminAllowlist).length > 0) {
const filteredMcpServers: Record<string, MCPServerConfig> = {};
for (const [serverId, localConfig] of Object.entries(mcpServers)) {
const adminConfig = adminAllowlist[serverId];
if (adminConfig) {
const mergedConfig = {
...localConfig,
url: adminConfig.url,
type: adminConfig.type,
trust: adminConfig.trust,
};
// Remove local connection details
delete mergedConfig.command;
delete mergedConfig.args;
delete mergedConfig.env;
delete mergedConfig.cwd;
delete mergedConfig.httpUrl;
delete mergedConfig.tcp;
if (
(adminConfig.includeTools && adminConfig.includeTools.length > 0) ||
(adminConfig.excludeTools && adminConfig.excludeTools.length > 0)
) {
mergedConfig.includeTools = adminConfig.includeTools;
mergedConfig.excludeTools = adminConfig.excludeTools;
}
filteredMcpServers[serverId] = mergedConfig;
}
}
mcpServers = filteredMcpServers;
const result = applyAdminAllowlist(mcpServers, adminAllowlist);
mcpServers = result.mcpServers;
mcpServerCommand = undefined;
if (result.blockedServerNames && result.blockedServerNames.length > 0) {
const message = getAdminBlockedMcpServersMessage(
result.blockedServerNames,
undefined,
);
coreEvents.emitConsoleLog('warn', message);
}
}
return new Config({

View File

@@ -48,6 +48,8 @@ import {
type HookEventName,
type ResolvedExtensionSetting,
coreEvents,
applyAdminAllowlist,
getAdminBlockedMcpServersMessage,
} from '@google/gemini-cli-core';
import { maybeRequestConsentOrFail } from './extensions/consent.js';
import { resolveEnvVarsInObject } from '../utils/envVarResolver.js';
@@ -661,12 +663,33 @@ Would you like to attempt to install via "git clone" instead?`,
if (this.settings.admin.mcp.enabled === false) {
config.mcpServers = undefined;
} else {
config.mcpServers = Object.fromEntries(
Object.entries(config.mcpServers).map(([key, value]) => [
key,
filterMcpConfig(value),
]),
);
// Apply admin allowlist if configured
const adminAllowlist = this.settings.admin.mcp.config;
if (adminAllowlist && Object.keys(adminAllowlist).length > 0) {
const result = applyAdminAllowlist(
config.mcpServers,
adminAllowlist,
);
config.mcpServers = result.mcpServers;
if (result.blockedServerNames.length > 0) {
const message = getAdminBlockedMcpServersMessage(
result.blockedServerNames,
undefined,
);
coreEvents.emitConsoleLog('warn', message);
}
}
// Then apply local filtering/sanitization
if (config.mcpServers) {
config.mcpServers = Object.fromEntries(
Object.entries(config.mcpServers).map(([key, value]) => [
key,
filterMcpConfig(value),
]),
);
}
}
}