import { FolderOpen, Globe, X } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; import type { FormEvent } from 'react'; import { useTranslation } from 'react-i18next'; import { Button, Input } from '../../../../shared/view/ui'; import { DEFAULT_CLAUDE_MCP_FORM } from '../../constants/constants'; import type { ClaudeMcpFormState, McpServer, McpScope, McpTransportType, SettingsProject } from '../../types/types'; type ClaudeMcpFormModalProps = { isOpen: boolean; editingServer: McpServer | null; projects: SettingsProject[]; onClose: () => void; onSubmit: (formData: ClaudeMcpFormState, editingServer: McpServer | null) => Promise; }; const getSafeTransportType = (value: unknown): McpTransportType => { if (value === 'sse' || value === 'http') { return value; } return 'stdio'; }; const getSafeScope = (value: unknown): McpScope => (value === 'local' ? 'local' : 'user'); const getErrorMessage = (error: unknown): string => ( error instanceof Error ? error.message : 'Unknown error' ); const createFormStateFromServer = (server: McpServer): ClaudeMcpFormState => ({ name: server.name || '', type: getSafeTransportType(server.type), scope: getSafeScope(server.scope), projectPath: server.projectPath || '', config: { command: server.config?.command || '', args: server.config?.args || [], env: server.config?.env || {}, url: server.config?.url || '', headers: server.config?.headers || {}, timeout: server.config?.timeout || 30000, }, importMode: 'form', jsonInput: '', raw: server.raw, }); export default function ClaudeMcpFormModal({ isOpen, editingServer, projects, onClose, onSubmit, }: ClaudeMcpFormModalProps) { const { t } = useTranslation('settings'); const [formData, setFormData] = useState(DEFAULT_CLAUDE_MCP_FORM); const [jsonValidationError, setJsonValidationError] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const isEditing = Boolean(editingServer); useEffect(() => { if (!isOpen) { return; } setJsonValidationError(''); if (editingServer) { setFormData(createFormStateFromServer(editingServer)); return; } setFormData(DEFAULT_CLAUDE_MCP_FORM); }, [editingServer, isOpen]); const canSubmit = useMemo(() => { if (!formData.name.trim()) { return false; } if (formData.importMode === 'json') { return Boolean(formData.jsonInput.trim()) && !jsonValidationError; } if (formData.scope === 'local' && !formData.projectPath.trim()) { return false; } if (formData.type === 'stdio') { return Boolean(formData.config.command.trim()); } return Boolean(formData.config.url.trim()); }, [formData, jsonValidationError]); if (!isOpen) { return null; } const updateConfig = ( key: K, value: ClaudeMcpFormState['config'][K], ) => { setFormData((prev) => ({ ...prev, config: { ...prev.config, [key]: value, }, })); }; const handleJsonValidation = (value: string) => { if (!value.trim()) { setJsonValidationError(''); return; } try { const parsed = JSON.parse(value) as { type?: string; command?: string; url?: string }; if (!parsed.type) { setJsonValidationError(t('mcpForm.validation.missingType')); } else if (parsed.type === 'stdio' && !parsed.command) { setJsonValidationError(t('mcpForm.validation.stdioRequiresCommand')); } else if ((parsed.type === 'http' || parsed.type === 'sse') && !parsed.url) { setJsonValidationError(t('mcpForm.validation.httpRequiresUrl', { type: parsed.type })); } else { setJsonValidationError(''); } } catch { setJsonValidationError(t('mcpForm.validation.invalidJson')); } }; const handleSubmit = async (event: FormEvent) => { event.preventDefault(); setIsSubmitting(true); try { await onSubmit(formData, editingServer); } catch (error) { alert(`Error: ${getErrorMessage(error)}`); } finally { setIsSubmitting(false); } }; return (

{isEditing ? t('mcpForm.title.edit') : t('mcpForm.title.add')}

{!isEditing && (
)} {formData.importMode === 'form' && isEditing && (
{formData.scope === 'user' ? : } {formData.scope === 'user' ? t('mcpForm.scope.userGlobal') : t('mcpForm.scope.projectLocal')} {formData.scope === 'local' && formData.projectPath && ( - {formData.projectPath} )}

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

)} {formData.importMode === 'form' && !isEditing && (

{formData.scope === 'user' ? t('mcpForm.scope.userDescription') : t('mcpForm.scope.projectDescription')}

{formData.scope === 'local' && (
{formData.projectPath && (

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

)}
)}
)}
setFormData((prev) => ({ ...prev, name: event.target.value }))} placeholder={t('mcpForm.placeholders.serverName')} required />
{formData.importMode === 'form' && (
)}
{isEditing && Boolean(formData.raw) && formData.importMode === 'form' && (

{t('mcpForm.configDetails', { configFile: editingServer?.scope === 'global' ? '~/.claude.json' : 'project config', })}

                {JSON.stringify(formData.raw, null, 2)}
              
)} {formData.importMode === 'json' && (