UNPKG

mcp-quiz-server

Version:

๐Ÿง  AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

254 lines (226 loc) โ€ข 8.66 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SSE MCP Client Test</title> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; background: #f5f5f5; } .container { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .status { padding: 10px; border-radius: 4px; margin: 10px 0; font-weight: bold; } .connected { background: #d4edda; color: #155724; } .disconnected { background: #f8d7da; color: #721c24; } .warning { background: #fff3cd; color: #856404; } .log { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 4px; padding: 15px; height: 300px; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; } .controls { margin: 20px 0; } button { background: #007bff; color: white; border: none; padding: 10px 15px; border-radius: 4px; cursor: pointer; margin: 5px; } button:hover { background: #0056b3; } button:disabled { background: #6c757d; cursor: not-allowed; } .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0; } .stat-card { background: #e9ecef; padding: 15px; border-radius: 4px; text-align: center; } .stat-number { font-size: 24px; font-weight: bold; color: #007bff; } </style> </head> <body> <div class="container"> <h1>๐ŸŒ SSE MCP Transport Test Client</h1> <div id="status" class="status disconnected"> โŒ Disconnected </div> <div class="stats"> <div class="stat-card"> <div class="stat-number" id="messageCount">0</div> <div>Messages Received</div> </div> <div class="stat-card"> <div class="stat-number" id="uptime">00:00:00</div> <div>Connection Time</div> </div> <div class="stat-card"> <div class="stat-number" id="mcpCalls">0</div> <div>MCP Calls Made</div> </div> </div> <div class="controls"> <button id="connectBtn" onclick="connect()">๐Ÿ”Œ Connect</button> <button id="disconnectBtn" onclick="disconnect()" disabled>๐Ÿ”Œ Disconnect</button> <button id="testMcpBtn" onclick="testMCP()" disabled>๐Ÿงช Test MCP Call</button> <button onclick="clearLog()">๐Ÿงน Clear Log</button> </div> <h3>๐Ÿ“‹ Event Log</h3> <div id="log" class="log"></div> </div> <script> let eventSource = null; let messageCount = 0; let mcpCalls = 0; let startTime = null; let uptimeInterval = null; const SSE_URL = 'http://localhost:3001/sse'; const MCP_URL = 'http://localhost:3001/mcp'; function log(message) { const logEl = document.getElementById('log'); const timestamp = new Date().toLocaleTimeString(); logEl.textContent += `[${timestamp}] ${message}\\n`; logEl.scrollTop = logEl.scrollHeight; } function updateStatus(connected) { const statusEl = document.getElementById('status'); const connectBtn = document.getElementById('connectBtn'); const disconnectBtn = document.getElementById('disconnectBtn'); const testMcpBtn = document.getElementById('testMcpBtn'); if (connected) { statusEl.className = 'status connected'; statusEl.textContent = 'โœ… Connected to SSE Transport'; connectBtn.disabled = true; disconnectBtn.disabled = false; testMcpBtn.disabled = false; startTime = Date.now(); uptimeInterval = setInterval(updateUptime, 1000); } else { statusEl.className = 'status disconnected'; statusEl.textContent = 'โŒ Disconnected'; connectBtn.disabled = false; disconnectBtn.disabled = true; testMcpBtn.disabled = true; if (uptimeInterval) { clearInterval(uptimeInterval); uptimeInterval = null; } } } function updateUptime() { if (!startTime) return; const elapsed = Math.floor((Date.now() - startTime) / 1000); const hours = Math.floor(elapsed / 3600).toString().padStart(2, '0'); const minutes = Math.floor((elapsed % 3600) / 60).toString().padStart(2, '0'); const seconds = (elapsed % 60).toString().padStart(2, '0'); document.getElementById('uptime').textContent = `${hours}:${minutes}:${seconds}`; } function connect() { if (eventSource) { log('โŒ Already connected'); return; } log('๐Ÿ”Œ Connecting to SSE server...'); eventSource = new EventSource(SSE_URL); eventSource.onopen = function() { log('โœ… SSE connection established'); updateStatus(true); }; eventSource.onmessage = function(event) { messageCount++; document.getElementById('messageCount').textContent = messageCount; try { const data = JSON.parse(event.data); log(`๐Ÿ“จ ${data.type}: ${data.message || JSON.stringify(data)}`); } catch (e) { log(`๐Ÿ“จ Raw message: ${event.data}`); } }; eventSource.onerror = function(error) { log('โŒ SSE connection error'); console.error('SSE Error:', error); updateStatus(false); eventSource = null; }; } function disconnect() { if (eventSource) { eventSource.close(); eventSource = null; log('๐Ÿ”Œ Disconnected from SSE server'); updateStatus(false); } } async function testMCP() { if (!eventSource) { log('โŒ Not connected to SSE server'); return; } const request = { jsonrpc: '2.0', id: Date.now(), method: 'tools/list', params: {} }; try { log('๐Ÿงช Sending MCP request...'); const response = await fetch(MCP_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(request) }); const result = await response.json(); mcpCalls++; document.getElementById('mcpCalls').textContent = mcpCalls; log(`โœ… MCP response: ${JSON.stringify(result, null, 2)}`); } catch (error) { log(`โŒ MCP request failed: ${error.message}`); } } function clearLog() { document.getElementById('log').textContent = ''; } // Auto-connect on page load window.onload = function() { log('๐ŸŒ SSE MCP Test Client loaded'); log('Click "Connect" to start SSE transport test'); }; // Cleanup on page unload window.onbeforeunload = function() { if (eventSource) { eventSource.close(); } }; </script> </body> </html>