import { Edit3, ExternalLink, Globe, Lock, Plus, Server, Terminal, Trash2, Users, Zap } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { McpProject, McpProvider, McpScope, ProviderMcpServer } from '../types'; import { IS_PLATFORM } from '../../../constants/config'; import { Badge, Button } from '../../../shared/view/ui'; import { MCP_GLOBAL_SUPPORTED_SCOPES, MCP_GLOBAL_SUPPORTED_TRANSPORTS, MCP_PROVIDER_BUTTON_CLASSES, MCP_PROVIDER_NAMES, } from '../constants'; import { useMcpServers } from '../hooks/useMcpServers'; import { maskSecret } from '../utils/mcpFormatting'; import McpServerFormModal from './modals/McpServerFormModal'; type McpServersProps = { selectedProvider: McpProvider; currentProjects: McpProject[]; }; const getTransportIcon = (transport: string | undefined) => { if (transport === 'stdio') { return ; } if (transport === 'sse') { return ; } if (transport === 'http') { return ; } return ; }; const getScopeLabel = (scope: McpScope): string => { if (scope === 'user') { return 'user'; } if (scope === 'local') { return 'local'; } return 'project'; }; const getServerKey = (server: ProviderMcpServer): string => ( `${server.provider}:${server.scope}:${server.workspacePath || 'global'}:${server.name}` ); function ConfigLine({ label, children }: { label: string; children: string }) { if (!children) { return null; } return (
{label}:{' '} {children}
); } function TeamMcpFeatureCard() { return (

Team MCP Configs

Share MCP server configurations across your team. Everyone stays in sync automatically.

Available with CloudCLI Pro
); } export default function McpServers({ selectedProvider, currentProjects }: McpServersProps) { const { t } = useTranslation('settings'); const { servers, isLoading, isLoadingProjectScopes, loadError, deleteError, saveStatus, isFormOpen, isGlobalFormOpen, editingServer, openForm, openGlobalForm, closeForm, closeGlobalForm, submitForm, submitGlobalForm, deleteServer, } = useMcpServers({ selectedProvider, currentProjects }); const providerName = MCP_PROVIDER_NAMES[selectedProvider]; const description = t(`mcpServers.description.${selectedProvider}`, { defaultValue: `Model Context Protocol servers provide additional tools and data sources to ${providerName}`, }); const globalButtonLabel = 'Add Global MCP Server'; const providerButtonLabel = `Add ${providerName} MCP Server`; const globalAddDescription = 'Add Global MCP Server writes one common stdio or HTTP server to Claude, Cursor, Codex, and Gemini.'; const providerAddDescription = `${providerButtonLabel} only changes ${providerName}.`; const globalModalDescription = 'Adds this MCP server to every provider: Claude, Cursor, Codex, and Gemini. ' + 'Only stdio and HTTP transports are supported because the same config must work across all providers.'; return (

{t('mcpServers.title')}

{description}

{saveStatus === 'success' && ( {t('saveStatus.success')} )} {isLoadingProjectScopes && ( Refreshing project scopes... )}
{(loadError || deleteError) && (
{deleteError || loadError}
)}
{isLoading && servers.length === 0 && (
Loading MCP servers...
)} {servers.map((server) => (
{getTransportIcon(server.transport)} {server.name} {server.transport || 'stdio'} {getScopeLabel(server.scope)} {server.projectDisplayName && ( {server.projectDisplayName} )}
{server.command || ''} {server.url || ''} {(server.args || []).join(' ')} {server.cwd || ''} {server.env && Object.keys(server.env).length > 0 && ( {Object.entries(server.env).map(([key, value]) => `${key}=${maskSecret(value)}`).join(', ')} )} {server.envVars && server.envVars.length > 0 && ( {server.envVars.join(', ')} )}
))} {!isLoading && !isLoadingProjectScopes && servers.length === 0 && (
{t('mcpServers.empty')}
)}
{selectedProvider === 'codex' && (

{t('mcpServers.help.title')}

{t('mcpServers.help.description')}

)} {selectedProvider === 'claude' && !IS_PLATFORM && } submitGlobalForm(formData)} />
); }