MCP DuckDuckGo Search Server

by spences10
Verified
import axios from 'axios' const api = axios.create({ baseURL: '/api', }) export interface ServerStatus { status: string activeClients: number uptime: string version: string } export interface ConnectionHistory { time: string connections: number } export interface ServiceConfig { enabled: boolean config: Record<string, string> } export interface Settings { server: { host: string port: number maxConnections: number pingTimeout: number debugMode: boolean sslEnabled: boolean } mcp: { protocolVersion: string maxContextLength: number defaultTemperature: number maxTokens: number } } // Server status and monitoring export const getServerStatus = () => api.get<ServerStatus>('/status') export const getConnectionHistory = () => api.get<ConnectionHistory[]>('/connections/history') export const getActiveClients = () => api.get('/clients') export const disconnectClient = (clientId: string) => api.post(`/clients/${clientId}/disconnect`) // Service management export const getServiceConfig = (serviceId: string) => api.get<ServiceConfig>(`/services/${serviceId}`) export const updateServiceConfig = (serviceId: string, config: ServiceConfig) => api.put(`/services/${serviceId}`, config) export const toggleService = (serviceId: string, enabled: boolean) => api.post(`/services/${serviceId}/toggle`, { enabled }) // Settings management export const getSettings = () => api.get<Settings>('/settings') export const updateSettings = (settings: Settings) => api.put('/settings', settings) // WebSocket singleton manager class WebSocketManager { private static instance: WebSocketManager; private ws: WebSocket | null = null; private reconnectTimeout: NodeJS.Timeout | null = null; private pingInterval: NodeJS.Timeout | null = null; private listeners: Set<(data: any) => void> = new Set(); private clientId: string; private isReconnecting: boolean = false; private constructor() { // Generate a stable client ID that persists across page reloads this.clientId = localStorage.getItem('mcp_client_id') || this.generateClientId(); localStorage.setItem('mcp_client_id', this.clientId); } private generateClientId(): string { return 'mcp-' + Math.random().toString(36).substring(2, 15); } static getInstance(): WebSocketManager { if (!WebSocketManager.instance) { WebSocketManager.instance = new WebSocketManager(); } return WebSocketManager.instance; } private startPingInterval() { if (this.pingInterval) { clearInterval(this.pingInterval); } this.pingInterval = setInterval(() => { if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send('ping'); } }, 30000); // Send ping every 30 seconds } connect() { if (this.ws?.readyState === WebSocket.OPEN || this.isReconnecting) return; this.isReconnecting = true; const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; this.ws = new WebSocket(`${protocol}//${window.location.host}/ws/${this.clientId}`); this.ws.onopen = () => { console.log('WebSocket connected'); this.isReconnecting = false; if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout); this.reconnectTimeout = null; } this.startPingInterval(); }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); this.isReconnecting = false; }; this.ws.onclose = () => { console.log('WebSocket disconnected'); this.isReconnecting = false; this.ws = null; if (this.pingInterval) { clearInterval(this.pingInterval); this.pingInterval = null; } // Attempt to reconnect after 5 seconds if we still have listeners if (!this.reconnectTimeout && this.listeners.size > 0) { this.reconnectTimeout = setTimeout(() => { if (this.listeners.size > 0) { this.connect(); } }, 5000); } }; this.ws.onmessage = (event) => { try { if (event.data === 'pong') { // Received pong response, connection is healthy return; } const data = JSON.parse(event.data); this.listeners.forEach(listener => listener(data)); } catch (error) { console.error('Error parsing WebSocket message:', error); } }; } addListener(listener: (data: any) => void) { this.listeners.add(listener); if (!this.ws && !this.isReconnecting) { this.connect(); } return () => this.removeListener(listener); } removeListener(listener: (data: any) => void) { this.listeners.delete(listener); if (this.listeners.size === 0) { if (this.ws) { this.ws.close(1000, "No active listeners"); this.ws = null; } if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout); this.reconnectTimeout = null; } if (this.pingInterval) { clearInterval(this.pingInterval); this.pingInterval = null; } } } } // Update createWebSocket to use the singleton manager export const createWebSocket = () => { const wsManager = WebSocketManager.getInstance(); wsManager.connect(); return { onmessage: (callback: (data: any) => void) => wsManager.addListener(callback), close: () => {}, // No-op since connection is managed by the singleton }; }; export default api