Opik MCP Server
Official
by comet-ml
- 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>