import { FileText, Globe, RefreshCw, Wrench } from 'lucide-react'; import { useCallback, useEffect, useState } from 'react'; import { useConfigStore } from '../../store/configStore'; import { silentErrorHandler } from '../../lib/error-utils'; import { listMcpServices, startMcpService, stopMcpService, type McpServiceConfig, type McpServiceStatus, type McpToolInfo, } from '../../lib/mcp-client'; export function MCPServices() { const quickConfig = useConfigStore((s) => s.quickConfig); const saveQuickConfig = useConfigStore((s) => s.saveQuickConfig); const services = quickConfig.mcpServices || []; const [runningServices, setRunningServices] = useState([]); const [loading, setLoading] = useState(null); const [expandedTools, setExpandedTools] = useState>(new Set()); // Fetch running services on mount const refreshRunning = useCallback(async () => { try { const running = await listMcpServices(); setRunningServices(running); } catch { // MCP might not be available yet setRunningServices([]); } }, []); useEffect(() => { refreshRunning(); }, [refreshRunning]); const toggleTools = (name: string) => { setExpandedTools((prev) => { const next = new Set(prev); if (next.has(name)) next.delete(name); else next.add(name); return next; }); }; const toggleService = async (id: string) => { const svc = services.find((s) => s.id === id); if (!svc) return; setLoading(id); try { if (svc.enabled) { // Currently enabled → stop it await stopMcpService(svc.name || svc.id).catch(() => {}); } else { // Currently disabled → start it const config: McpServiceConfig = { name: svc.name || svc.id, command: svc.command || '', args: svc.args, env: svc.env, cwd: svc.cwd, }; await startMcpService(config); } // Update config flag const nextServices = services.map((s) => s.id === id ? { ...s, enabled: !s.enabled } : s ); await saveQuickConfig({ mcpServices: nextServices }); // Refresh running status await refreshRunning(); } catch (err) { console.error('[MCP] Toggle failed:', err); } finally { setLoading(null); } }; // Build a map of service name → running status for quick lookup const runningMap = new Map(runningServices.map((rs) => [rs.name, rs])); return (

MCP 服务

{runningServices.length} 个运行中 / {services.length} 个已声明
MCP(模型上下文协议)服务为 Agent 扩展外部工具 — 文件系统、数据库、网页搜索等。
{services.length > 0 ? services.map((svc) => { const isRunning = runningMap.has(svc.name || svc.id); const status = runningMap.get(svc.name || svc.id); const isLoading = loading === svc.id; const showTools = expandedTools.has(svc.id); return (
{svc.id === 'filesystem' ? : }
{svc.name}
{svc.id} {svc.command && ( | )} {svc.command && ( {svc.command} )}
{isRunning && status && ( )} {isLoading ? '处理中...' : isRunning ? '运行中' : svc.enabled ? '已启用' : '已停用'}
{/* Expanded tools list */} {showTools && status && status.tools.length > 0 && (
已发现的工具:
{status.tools.map((tool: McpToolInfo) => (
{tool.tool_name} {tool.description && ( {tool.description} )}
))}
)}
); }) : (
尚未配置 MCP 服务
MCP 服务为 Agent 扩展外部工具能力。可通过编辑配置文件 config/mcp.toml 添加服务。
)}
新增/删除服务尚未在桌面端 UI 接入。可通过编辑 config/mcp.toml 手动添加 MCP 服务配置,重启后生效。
); }