import { FolderOpen, Globe, X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { Button, Input } from '../../../../shared/view/ui'; import { MCP_PROVIDER_NAMES, MCP_SUPPORTED_SCOPES, MCP_SUPPORTED_TRANSPORTS, MCP_SUPPORTS_WORKING_DIRECTORY, } from '../../constants'; import { useMcpServerForm } from '../../hooks/useMcpServerForm'; import type { McpFormMode, McpFormState, McpProject, McpProvider, McpScope, McpTransport, ProviderMcpServer, } from '../../types'; type McpServerFormModalProps = { provider: McpProvider; mode?: McpFormMode; isOpen: boolean; editingServer: ProviderMcpServer | null; currentProjects: McpProject[]; title?: string; description?: string; submitLabel?: string; supportedScopes?: McpScope[]; supportedTransports?: McpTransport[]; onClose: () => void; onSubmit: (formData: McpFormState, editingServer: ProviderMcpServer | null) => Promise; }; const getScopeLabel = (scope: McpScope, mode: McpFormMode): string => { if (scope === 'user') { return mode === 'global' ? 'User (All Providers)' : 'User (Global)'; } if (scope === 'local') { return 'Claude Local'; } return mode === 'global' ? 'Project (All Providers)' : 'Project'; }; const getScopeDescription = (scope: McpScope, mode: McpFormMode): string => { if (scope === 'user') { return mode === 'global' ? 'Writes to each provider user config and is available across projects on this machine' : 'Available across all projects on your machine'; } if (scope === 'local') { return 'Stored in Claude user settings for the selected project'; } return mode === 'global' ? 'Writes to the selected project workspace for every provider' : 'Stored in the selected project workspace'; }; export default function McpServerFormModal({ provider, mode = 'provider', isOpen, editingServer, currentProjects, title, description, submitLabel, supportedScopes, supportedTransports, onClose, onSubmit, }: McpServerFormModalProps) { const { t } = useTranslation('settings'); const isGlobalMode = mode === 'global'; const availableScopes = supportedScopes ?? MCP_SUPPORTED_SCOPES[provider]; const availableTransports = supportedTransports ?? MCP_SUPPORTED_TRANSPORTS[provider]; const { formData, multilineText, projectOptions, isEditing, isSubmitting, jsonValidationError, canSubmit, updateForm, updateScope, updateTransport, updateJsonInput, updateMultilineText, handleSubmit, } = useMcpServerForm({ provider, isOpen, editingServer, currentProjects, supportedScopes: availableScopes, supportedTransports: availableTransports, unsupportedTransportMessage: isGlobalMode ? (transport) => `Add MCP Server supports only stdio and http across all providers, not ${transport}.` : undefined, onSubmit, }); if (!isOpen) { return null; } const providerName = MCP_PROVIDER_NAMES[provider]; const modalTitle = title ?? (isEditing ? t('mcpForm.title.edit') : t('mcpForm.title.add')); const addButtonLabel = submitLabel ?? `${t('mcpForm.actions.addServer')} to ${providerName}`; const showProjectSelector = formData.scope !== 'user'; const supportsHttpHeaders = formData.transport === 'http' || formData.transport === 'sse'; const supportsWorkingDirectory = !isGlobalMode && MCP_SUPPORTS_WORKING_DIRECTORY[provider]; const showCodexOnlyFields = provider === 'codex' && !isGlobalMode; return (

{modalTitle}

{description && (
{description}
)} {!isEditing && (
)} {isEditing && (
{formData.scope === 'user' ? : } {getScopeLabel(formData.scope, mode)} {formData.workspacePath && ( - {formData.workspacePath} )}

{t('mcpForm.scope.cannotChange')}

)} {!isEditing && (
{availableScopes.map((scope) => ( ))}

{getScopeDescription(formData.scope, mode)}

{showProjectSelector && (
{formData.workspacePath && (

{t('mcpForm.projectPath', { path: formData.workspacePath })}

)}
)}
)}
updateForm('name', event.target.value)} placeholder={t('mcpForm.placeholders.serverName')} required />
{formData.importMode === 'form' && (
)}
{formData.importMode === 'json' && (