Opik MCP Server

Official
  • client
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>MCP SSE Client</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; line-height: 1.6; margin: 0; padding: 20px; color: #333; max-width: 1200px; margin: 0 auto; } h1, h2, h3 { color: #0066cc; } #messages { height: 300px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; margin-bottom: 20px; background-color: #f9f9f9; border-radius: 4px; font-family: monospace; } #message-form { margin-bottom: 20px; } textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; min-height: 100px; font-family: monospace; margin-bottom: 10px; } button { background-color: #0066cc; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; } button:hover { background-color: #0055aa; } .message { margin-bottom: 8px; border-bottom: 1px solid #eee; padding-bottom: 8px; } .message-time { color: #666; font-size: 12px; } .message-direction { display: inline-block; padding: 2px 6px; border-radius: 3px; font-size: 12px; margin-right: 8px; } .direction-incoming { background-color: #e7f3ff; color: #0066cc; } .direction-outgoing { background-color: #e7ffe7; color: #007700; } .message-content { white-space: pre-wrap; background-color: #fff; padding: 8px; border-radius: 4px; overflow-x: auto; } .connection-info { margin-bottom: 20px; padding: 10px; background-color: #f0f0f0; border-radius: 4px; } .status { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: 8px; } .status-connected { background-color: #00cc00; } .status-disconnected { background-color: #cc0000; } </style> </head> <body> <h1>MCP SSE Client</h1> <div class="connection-info"> <div id="connection-status"> <span class="status status-disconnected"></span> Disconnected </div> <div> <label for="server-url">Server URL:</label> <input type="text" id="server-url" value="http://localhost:3001" style="width: 250px;"> <button id="connect-btn">Connect</button> <button id="disconnect-btn" disabled>Disconnect</button> </div> </div> <h2>Send Message</h2> <div id="message-form"> <textarea id="message-input" placeholder="Enter your JSON message here..."> { "jsonrpc": "2.0", "method": "mcp__get_server_info", "id": "1", "params": {} } </textarea> <button id="send-btn" disabled>Send Message</button> </div> <h2>Messages</h2> <div id="messages"></div> <script> let eventSource = null; const messagesContainer = document.getElementById('messages'); const messageInput = document.getElementById('message-input'); const sendBtn = document.getElementById('send-btn'); const connectBtn = document.getElementById('connect-btn'); const disconnectBtn = document.getElementById('disconnect-btn'); const serverUrlInput = document.getElementById('server-url'); const connectionStatus = document.getElementById('connection-status'); // Function to connect to the SSE server function connect() { const serverUrl = serverUrlInput.value.trim(); if (!serverUrl) { alert('Please enter a valid server URL'); return; } try { // Generate a unique client ID const clientId = 'client_' + Date.now(); // Create a new EventSource eventSource = new EventSource(`${serverUrl}/events?clientId=${clientId}`); // Listen for messages eventSource.onmessage = (event) => { const data = event.data; addMessage('incoming', data); }; // Handle connection open eventSource.onopen = () => { connectionStatus.innerHTML = '<span class="status status-connected"></span> Connected'; connectBtn.disabled = true; disconnectBtn.disabled = false; sendBtn.disabled = false; addMessage('system', 'Connected to server'); }; // Handle errors eventSource.onerror = (error) => { console.error('EventSource error:', error); addMessage('system', 'Connection error. Reconnecting...'); connectionStatus.innerHTML = '<span class="status status-disconnected"></span> Error connecting'; }; } catch (error) { console.error('Error connecting to server:', error); addMessage('system', `Error connecting: ${error.message}`); } } // Function to disconnect from the SSE server function disconnect() { if (eventSource) { eventSource.close(); eventSource = null; connectionStatus.innerHTML = '<span class="status status-disconnected"></span> Disconnected'; connectBtn.disabled = false; disconnectBtn.disabled = true; sendBtn.disabled = true; addMessage('system', 'Disconnected from server'); } } // Function to send a message to the server async function sendMessage() { const message = messageInput.value.trim(); if (!message) { alert('Please enter a message to send'); return; } try { // Parse message to validate JSON const jsonMessage = JSON.parse(message); // Send the message to the server const serverUrl = serverUrlInput.value.trim(); const response = await fetch(`${serverUrl}/send`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: message, }); const responseData = await response.json(); if (response.ok) { addMessage('outgoing', message); } else { addMessage('system', `Error sending message: ${responseData.message || 'Unknown error'}`); } } catch (error) { console.error('Error sending message:', error); addMessage('system', `Error sending message: ${error.message}`); } } // Function to add a message to the messages container function addMessage(direction, content) { const messageDiv = document.createElement('div'); messageDiv.className = 'message'; const now = new Date(); const time = now.toLocaleTimeString(); let directionLabel = ''; let directionClass = ''; switch (direction) { case 'incoming': directionLabel = 'Received'; directionClass = 'direction-incoming'; break; case 'outgoing': directionLabel = 'Sent'; directionClass = 'direction-outgoing'; break; case 'system': directionLabel = 'System'; directionClass = ''; break; } let contentDisplay = content; // Try to pretty-print JSON if it's not a system message if (direction !== 'system') { try { contentDisplay = JSON.stringify(JSON.parse(content), null, 2); } catch (e) { // Not valid JSON, just use as-is } } messageDiv.innerHTML = ` <div> <span class="message-time">${time}</span> <span class="message-direction ${directionClass}">${directionLabel}</span> </div> <div class="message-content">${direction === 'system' ? content : contentDisplay}</div> `; messagesContainer.appendChild(messageDiv); // Auto-scroll to bottom messagesContainer.scrollTop = messagesContainer.scrollHeight; } // Set up event listeners connectBtn.addEventListener('click', connect); disconnectBtn.addEventListener('click', disconnect); sendBtn.addEventListener('click', sendMessage); // Allow pressing Enter in the input to send a message messageInput.addEventListener('keydown', (event) => { if (event.key === 'Enter' && event.ctrlKey) { sendMessage(); event.preventDefault(); } }); // Add a welcome message addMessage('system', 'Welcome to the MCP SSE Client. Click Connect to start.'); </script> </body> </html>