import { AlertTriangle, ChevronDown, ChevronRight, FileText, Folder, Power, RotateCcw, Trash2, Wrench } from 'lucide-react' import { Notice } from 'obsidian' import React, { useEffect, useState } from 'react' import { useMcpHub } from '../../contexts/McpHubContext' import { useSettings } from '../../contexts/SettingsContext' import { McpErrorEntry, McpResource, McpResourceTemplate, McpServer, McpTool } from '../../core/mcp/type' import { t } from '../../lang/helpers' const McpHubView = () => { const { settings, setSettings } = useSettings() const { getMcpHub } = useMcpHub() const [mcpServers, setMcpServers] = useState([]) const [expandedServers, setExpandedServers] = useState>({}); const [activeServerDetailTab, setActiveServerDetailTab] = useState>({}); // 新增状态变量用于创建新服务器 const [newServerName, setNewServerName] = useState('') const [newServerConfig, setNewServerConfig] = useState('') const [isCreateSectionExpanded, setIsCreateSectionExpanded] = useState(false) const fetchServers = async () => { const hub = await getMcpHub() if (hub) { const serversData = hub.getAllServers() setMcpServers(serversData) } } useEffect(() => { fetchServers() }, [getMcpHub]) const switchMcp = React.useCallback(() => { setSettings({ ...settings, mcpEnabled: !settings.mcpEnabled, }) }, [settings, setSettings]) // const handleSearch = (e: React.ChangeEvent) => { // setSearchTerm(e.target.value) // } const handleRestart = async (serverName: string) => { const hub = await getMcpHub(); if (hub) { await hub.restartConnection(serverName, "global") const updatedServers = hub.getAllServers() setMcpServers(updatedServers) } } const handleToggle = async (serverName: string, disabled: boolean) => { const hub = await getMcpHub(); if (hub) { await hub.toggleServerDisabled(serverName, !disabled) const updatedServers = hub.getAllServers() setMcpServers(updatedServers) } } const handleDelete = async (serverName: string) => { const hub = await getMcpHub(); if (hub) { if (confirm(t('mcpHub.deleteConfirm').replace('{name}', serverName) as string)) { await hub.deleteServer(serverName, "global") const updatedServers = hub.getAllServers() setMcpServers(updatedServers) } } } const handleCreate = async () => { // 验证输入 if (newServerName.trim().length === 0) { new Notice(t('mcpHub.serverNameRequired')) return } if (newServerConfig.trim().length === 0) { new Notice(t('mcpHub.configRequired')) return } // check config is valid json try { JSON.parse(newServerConfig) } catch (error) { new Notice(t('mcpHub.invalidConfig')) return } const hub = await getMcpHub(); if (hub) { try { await hub.createServer(newServerName, newServerConfig, "global") const updatedServers = hub.getAllServers() setMcpServers(updatedServers) // 清空表单 setNewServerName('') setNewServerConfig('') new Notice(t('mcpHub.createSuccess').replace('{name}', newServerName) as string) } catch (error) { new Notice(t('mcpHub.createFailed').replace('{error}', error.message) as string) } } } const toggleServerExpansion = (serverKey: string) => { setExpandedServers(prev => ({ ...prev, [serverKey]: !prev[serverKey] })); if (!expandedServers[serverKey] && !activeServerDetailTab[serverKey]) { setActiveServerDetailTab(prev => ({ ...prev, [serverKey]: 'tools' })); } }; const handleDetailTabChange = (serverKey: string, tab: 'tools' | 'resources' | 'errors') => { setActiveServerDetailTab(prev => ({ ...prev, [serverKey]: tab })); }; const toggleCreateSectionExpansion = () => { setIsCreateSectionExpanded(prev => !prev) } const ToolRow = ({ tool }: { tool: McpTool }) => { return (
{tool.name}
{tool.description && (

{tool.description}

)} {(tool.inputSchema && (() => { const schema = tool.inputSchema; const properties = schema && typeof schema === 'object' && 'properties' in schema ? schema.properties : undefined; const required = schema && typeof schema === 'object' && 'required' in schema ? schema.required : undefined; if (properties && typeof properties === 'object' && Object.keys(properties).length > 0) { return (
{t('mcpHub.parameters')}
{Object.entries(properties).map( ([paramName, paramSchemaUntyped]) => { const paramSchema = paramSchemaUntyped && typeof paramSchemaUntyped === 'object' ? paramSchemaUntyped : {}; const paramDescription = 'description' in paramSchema && typeof paramSchema.description === 'string' ? paramSchema.description : undefined; const isRequired = required && Array.isArray(required) && required.includes(paramName); return (
{paramName} {isRequired && *} {paramDescription || t('mcpHub.toolNoDescription')}
); } )}
); } return null; })())}
); }; const ResourceRow = ({ resource }: { resource: McpResource | McpResourceTemplate }) => (
{'uri' in resource ? resource.uri : resource.uriTemplate}
{resource.description &&

{resource.description}

}
); const ErrorRow = ({ error }: { error: McpErrorEntry }) => (

{error.message}

{new Date(error.timestamp).toLocaleString()}

); return (
{/* Header Section */}

{t('mcpHub.title')}

{/* MCP Settings */}

{t('mcpHub.enableMcpDescription')} {t('mcpHub.learnMore')}

{/* Create New Server Section */} {settings.mcpEnabled && (
{isCreateSectionExpanded ? : }

{t('mcpHub.addNewServer')}

{isCreateSectionExpanded && (
{t('mcpHub.serverName')}
setNewServerName(e.target.value)} placeholder={t('mcpHub.serverNamePlaceholder')} className="infio-mcp-create-input" />
{t('mcpHub.config')}