"use client"; import { invoke } from "@tauri-apps/api/core"; import { Eye, EyeOff } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { useWayfernTerms } from "@/hooks/use-wayfern-terms"; import { showErrorToast, showSuccessToast } from "@/lib/toast-utils"; import { CopyToClipboard } from "./ui/copy-to-clipboard"; interface AppSettings { api_enabled: boolean; api_port: number; api_token?: string; mcp_enabled: boolean; mcp_port?: number; mcp_token?: string; } interface McpConfig { port: number; token: string; config_json: string; } interface IntegrationsDialogProps { isOpen: boolean; onClose: () => void; } export function IntegrationsDialog({ isOpen, onClose, }: IntegrationsDialogProps) { const [settings, setSettings] = useState({ api_enabled: false, api_port: 10108, api_token: undefined, mcp_enabled: false, mcp_port: undefined, mcp_token: undefined, }); const [apiServerPort, setApiServerPort] = useState(null); const [mcpConfig, setMcpConfig] = useState(null); const [_mcpRunning, setMcpRunning] = useState(false); const [showApiToken, setShowApiToken] = useState(false); const [showMcpToken, setShowMcpToken] = useState(false); const [isApiStarting, setIsApiStarting] = useState(false); const [isMcpStarting, setIsMcpStarting] = useState(false); const { termsAccepted } = useWayfernTerms(); const loadSettings = useCallback(async () => { try { const loaded = await invoke("get_app_settings"); setSettings(loaded); } catch (e) { console.error("Failed to load settings:", e); } }, []); const loadMcpConfig = useCallback(async () => { try { const config = await invoke("get_mcp_config"); setMcpConfig(config); } catch (e) { console.error("Failed to get MCP config:", e); } }, []); const loadMcpServerStatus = useCallback(async () => { try { const isRunning = await invoke("get_mcp_server_status"); setMcpRunning(isRunning); } catch (e) { console.error("Failed to get MCP server status:", e); } }, []); const loadApiServerStatus = useCallback(async () => { try { const port = await invoke("get_api_server_status"); setApiServerPort(port); } catch (e) { console.error("Failed to get API server status:", e); } }, []); useEffect(() => { if (isOpen) { loadSettings(); loadApiServerStatus(); loadMcpConfig(); loadMcpServerStatus(); } }, [ isOpen, loadSettings, loadApiServerStatus, loadMcpConfig, loadMcpServerStatus, ]); const handleApiToggle = async (enabled: boolean) => { setIsApiStarting(true); try { if (enabled) { const port = await invoke("start_api_server", { port: settings.api_port, }); setApiServerPort(port); const next = await invoke("save_app_settings", { settings: { ...settings, api_enabled: true }, }); setSettings(next); showSuccessToast(`API server started on port ${port}`); } else { await invoke("stop_api_server"); setApiServerPort(null); const next = await invoke("save_app_settings", { settings: { ...settings, api_enabled: false, api_token: null }, }); setSettings(next); showSuccessToast("API server stopped"); } } catch (e) { console.error("Failed to toggle API:", e); showErrorToast("Failed to toggle API server", { description: e instanceof Error ? e.message : "Unknown error", }); } finally { setIsApiStarting(false); } }; const handleMcpToggle = async (enabled: boolean) => { setIsMcpStarting(true); try { if (enabled) { const port = await invoke("start_mcp_server"); const next = await invoke("save_app_settings", { settings: { ...settings, mcp_enabled: true, mcp_port: port }, }); setSettings(next); loadMcpConfig(); showSuccessToast(`MCP server started on port ${port}`); } else { await invoke("stop_mcp_server"); const next = await invoke("save_app_settings", { settings: { ...settings, mcp_enabled: false }, }); setSettings(next); setMcpConfig(null); showSuccessToast("MCP server stopped"); } } catch (e) { console.error("Failed to toggle MCP server:", e); showErrorToast("Failed to toggle MCP server", { description: e instanceof Error ? e.message : "Unknown error", }); } finally { setIsMcpStarting(false); } }; const obfuscateToken = (token: string) => "•".repeat(Math.min(token.length, 32)); const getFormattedMcpConfig = () => { if (!mcpConfig) return ""; return JSON.stringify( { mcpServers: { "donut-browser": { url: `http://127.0.0.1:${mcpConfig.port}/mcp`, headers: { Authorization: `Bearer ${mcpConfig.token}`, }, }, }, }, null, 2, ); }; const getObfuscatedMcpConfig = () => { if (!mcpConfig) return ""; return JSON.stringify( { mcpServers: { "donut-browser": { url: `http://127.0.0.1:${mcpConfig.port}/mcp`, headers: { Authorization: `Bearer ${obfuscateToken(mcpConfig.token)}`, }, }, }, }, null, 2, ); }; return ( !open && onClose()}> Integrations
Local API MCP (AI Assistants)

Allow managing profiles, groups, and proxies via REST API.

{settings.api_enabled && (
Server is running

Include in Authorization header: Bearer {""}

)}

Allow AI assistants like Claude Desktop to control browsers. {!termsAccepted && ( (Accept Wayfern terms in Settings first) )}

{mcpConfig && (

Copy this configuration to your Claude Desktop config file at{" "} ~/.config/claude/claude_desktop_config.json

                      {showMcpToken
                        ? getFormattedMcpConfig()
                        : getObfuscatedMcpConfig()}
                    
  • list_profiles - List browser profiles
  • run_profile - Launch a browser
  • kill_profile - Stop a running browser
  • get_profile_status - Check if browser is running
  • list_groups, create_group, etc. - Manage groups
  • list_proxies, create_proxy, etc. - Manage proxies
)}
); }