/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import type { CommandModule } from 'yargs'; import { debugLogger } from '@google/gemini-cli-core'; import { McpServerEnablementManager, canLoadServer, normalizeServerId, } from '../../config/mcp/mcpServerEnablement.js'; import { loadSettings } from '../../config/settings.js'; import { exitCli } from '../utils.js'; import { getMcpServersFromConfig } from './list.js'; const GREEN = '\x1b[32m'; const YELLOW = '\x1b[33m'; const RED = '\x1b[31m'; const RESET = '\x1b[0m'; interface Args { name: string; session?: boolean; } async function handleEnable(args: Args): Promise { const manager = McpServerEnablementManager.getInstance(); const name = normalizeServerId(args.name); // Check settings blocks const settings = loadSettings(); // Get all servers including extensions const servers = await getMcpServersFromConfig(); const normalizedServerNames = Object.keys(servers).map(normalizeServerId); if (!normalizedServerNames.includes(name)) { debugLogger.log( `${RED}Error:${RESET} Server '${args.name}' not found. Use 'gemini mcp' to see available servers.`, ); return; } // Check if server is from an extension const serverKey = Object.keys(servers).find( (key) => normalizeServerId(key) === name, ); const server = serverKey ? servers[serverKey] : undefined; if (server?.extension) { debugLogger.log( `${RED}Error:${RESET} Server '${args.name}' is provided by extension '${server.extension.name}'.`, ); debugLogger.log( `Use 'gemini extensions enable ${server.extension.name}' to manage this extension.`, ); return; } const result = await canLoadServer(name, { adminMcpEnabled: settings.merged.admin?.mcp?.enabled ?? true, allowedList: settings.merged.mcp?.allowed, excludedList: settings.merged.mcp?.excluded, }); if ( !result.allowed && (result.blockType === 'allowlist' || result.blockType === 'excludelist') ) { debugLogger.log(`${RED}Error:${RESET} ${result.reason}`); return; } if (args.session) { manager.clearSessionDisable(name); debugLogger.log(`${GREEN}✓${RESET} Session disable cleared for '${name}'.`); } else { await manager.enable(name); debugLogger.log(`${GREEN}✓${RESET} MCP server '${name}' enabled.`); } if (result.blockType === 'admin') { debugLogger.log( `${YELLOW}Warning:${RESET} MCP servers are disabled by administrator.`, ); } } async function handleDisable(args: Args): Promise { const manager = McpServerEnablementManager.getInstance(); const name = normalizeServerId(args.name); // Get all servers including extensions const servers = await getMcpServersFromConfig(); const normalizedServerNames = Object.keys(servers).map(normalizeServerId); if (!normalizedServerNames.includes(name)) { debugLogger.log( `${RED}Error:${RESET} Server '${args.name}' not found. Use 'gemini mcp' to see available servers.`, ); return; } // Check if server is from an extension const serverKey = Object.keys(servers).find( (key) => normalizeServerId(key) === name, ); const server = serverKey ? servers[serverKey] : undefined; if (server?.extension) { debugLogger.log( `${RED}Error:${RESET} Server '${args.name}' is provided by extension '${server.extension.name}'.`, ); debugLogger.log( `Use 'gemini extensions disable ${server.extension.name}' to manage this extension.`, ); return; } if (args.session) { manager.disableForSession(name); debugLogger.log( `${GREEN}✓${RESET} MCP server '${name}' disabled for this session.`, ); } else { await manager.disable(name); debugLogger.log(`${GREEN}✓${RESET} MCP server '${name}' disabled.`); } } export const enableCommand: CommandModule = { command: 'enable ', describe: 'Enable an MCP server', builder: (yargs) => yargs .positional('name', { describe: 'MCP server name to enable', type: 'string', demandOption: true, }) .option('session', { describe: 'Clear session-only disable', type: 'boolean', default: false, }), handler: async (argv) => { await handleEnable(argv as Args); await exitCli(); }, }; export const disableCommand: CommandModule = { command: 'disable ', describe: 'Disable an MCP server', builder: (yargs) => yargs .positional('name', { describe: 'MCP server name to disable', type: 'string', demandOption: true, }) .option('session', { describe: 'Disable for current session only', type: 'boolean', default: false, }), handler: async (argv) => { await handleDisable(argv as Args); await exitCli(); }, };