// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT import { motion } from "framer-motion"; import { Blocks, PencilRuler, Trash } from "lucide-react"; import { useCallback, useState } from "react"; import { Tooltip } from "~/app/_components/tooltip"; import { Button } from "~/components/ui/button"; import { Switch } from "~/components/ui/switch"; import type { MCPServerMetadata } from "~/core/mcp"; import { cn } from "~/lib/utils"; import { AddMCPServerDialog } from "../dialogs/add-mcp-server-dialog"; import type { Tab } from "./types"; export const MCPTab: Tab = ({ settings, onChange }) => { const [servers, setServers] = useState( settings.mcp.servers, ); const [newlyAdded, setNewlyAdded] = useState(false); const handleAddServers = useCallback( (servers: MCPServerMetadata[]) => { const merged = mergeServers(settings.mcp.servers, servers); setServers(merged); onChange({ ...settings, mcp: { ...settings.mcp, servers: merged } }); setNewlyAdded(true); setTimeout(() => { setNewlyAdded(false); }, 1000); setTimeout(() => { document.getElementById("settings-content-scrollable")?.scrollTo({ top: 0, behavior: "smooth", }); }, 100); }, [onChange, settings], ); const handleDeleteServer = useCallback( (name: string) => { const merged = settings.mcp.servers.filter( (server) => server.name !== name, ); setServers(merged); onChange({ ...settings, mcp: { ...settings.mcp, servers: merged } }); }, [onChange, settings], ); const handleToggleServer = useCallback( (name: string, enabled: boolean) => { const merged = settings.mcp.servers.map((server) => server.name === name ? { ...server, enabled } : server, ); setServers(merged); onChange({ ...settings, mcp: { ...settings.mcp, servers: merged } }); }, [onChange, settings], ); const animationProps = { initial: { backgroundColor: "gray" }, animate: { backgroundColor: "transparent" }, transition: { duration: 1 }, style: { transition: "background-color 1s ease-out", }, }; return (

MCP Servers

The Model Context Protocol boosts DeerFlow by integrating external tools for tasks like private domain searches, web browsing, food ordering, and more. Click here to learn more about MCP.
    {servers.map((server) => { const isNew = server.createdAt && server.createdAt > Date.now() - 1000 * 60 * 60 * 1; return (
    { handleToggleServer(server.name, checked); }} />
    {server.name}
    {!server.enabled && (
    Disabled
    )}
    {server.transport}
    {isNew && (
    New
    )}
      {server.tools.map((tool) => (
    • {tool.name}
    • ))}
    ); })}
); }; MCPTab.icon = Blocks; MCPTab.badge = "Beta"; function mergeServers( existing: MCPServerMetadata[], added: MCPServerMetadata[], ): MCPServerMetadata[] { const serverMap = new Map(existing.map((server) => [server.name, server])); for (const addedServer of added) { addedServer.createdAt = Date.now(); addedServer.updatedAt = Date.now(); serverMap.set(addedServer.name, addedServer); } const result = Array.from(serverMap.values()); result.sort((a, b) => b.createdAt - a.createdAt); return result; }