Skip to main content
Glama

MCP Orchestration Server

mcp_interface.html28.5 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BlackHole Core MCP - Command Interface</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; min-height: 100vh; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; background: rgba(255,255,255,0.1); border-radius: 20px; padding: 30px; backdrop-filter: blur(10px); box-shadow: 0 8px 32px rgba(0,0,0,0.3); } .header { text-align: center; margin-bottom: 40px; } .header h1 { font-size: 2.5em; margin-bottom: 10px; background: linear-gradient(45deg, #fff, #f0f0f0); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .command-interface { display: grid; grid-template-columns: 1fr 400px 400px; gap: 30px; margin-bottom: 30px; } .command-input-section { background: rgba(255,255,255,0.1); border-radius: 15px; padding: 25px; } .command-input { width: 100%; padding: 15px; border: none; border-radius: 10px; background: rgba(255,255,255,0.2); color: white; font-size: 16px; margin-bottom: 15px; backdrop-filter: blur(5px); } .command-input::placeholder { color: rgba(255,255,255,0.7); } .command-buttons { display: flex; gap: 10px; flex-wrap: wrap; } .btn { padding: 12px 24px; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 600; transition: all 0.3s ease; text-transform: uppercase; letter-spacing: 0.5px; } .btn-primary { background: linear-gradient(45deg, #28a745, #20c997); color: white; } .btn-secondary { background: linear-gradient(45deg, #6c757d, #495057); color: white; } .btn-info { background: linear-gradient(45deg, #17a2b8, #138496); color: white; } .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 15px rgba(0,0,0,0.3); } .status-panel { background: rgba(255,255,255,0.1); border-radius: 15px; padding: 25px; } .status-item { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,0.2); } .status-item:last-child { border-bottom: none; } .status-indicator { padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: bold; } .status-online { background: #28a745; color: white; } .status-offline { background: #dc3545; color: white; } .results-section { background: rgba(255,255,255,0.1); border-radius: 15px; padding: 25px; margin-top: 30px; } .result-item { background: rgba(255,255,255,0.1); border-radius: 10px; padding: 20px; margin-bottom: 15px; border-left: 4px solid #28a745; } .result-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .result-command { font-weight: bold; color: #ffd700; } .result-timestamp { font-size: 12px; opacity: 0.8; } .result-content { background: rgba(0,0,0,0.2); border-radius: 8px; padding: 15px; font-family: 'Courier New', monospace; font-size: 14px; white-space: pre-wrap; max-height: 300px; overflow-y: auto; } .loading { display: none; text-align: center; padding: 20px; } .spinner { border: 3px solid rgba(255,255,255,0.3); border-radius: 50%; border-top: 3px solid white; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 0 auto 10px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .examples { margin-top: 15px; } .example-command { background: rgba(255,255,255,0.1); border-radius: 5px; padding: 8px 12px; margin: 5px 0; cursor: pointer; font-size: 14px; transition: background 0.3s ease; } .example-command:hover { background: rgba(255,255,255,0.2); } .file-upload-section { background: rgba(255,255,255,0.1); border-radius: 15px; padding: 25px; } .file-drop-zone { border: 2px dashed rgba(255,255,255,0.5); border-radius: 10px; padding: 30px; text-align: center; margin-bottom: 15px; transition: all 0.3s ease; cursor: pointer; min-height: 120px; display: flex; flex-direction: column; justify-content: center; align-items: center; } .file-drop-zone:hover { border-color: rgba(255,255,255,0.8); background: rgba(255,255,255,0.05); } .file-drop-zone.dragover { border-color: #28a745; background: rgba(40, 167, 69, 0.1); } .file-input { display: none; } .file-info { margin-top: 15px; padding: 10px; background: rgba(255,255,255,0.1); border-radius: 8px; font-size: 14px; } .processing-options { margin: 15px 0; } .checkbox-group { display: flex; flex-direction: column; gap: 10px; margin: 10px 0; } .checkbox-item { display: flex; align-items: center; gap: 8px; } .checkbox-item input[type="checkbox"] { width: 16px; height: 16px; } .checkbox-item label { font-size: 14px; cursor: pointer; } .upload-progress { display: none; margin: 15px 0; } .progress-bar { width: 100%; height: 8px; background: rgba(255,255,255,0.2); border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(45deg, #28a745, #20c997); width: 0%; transition: width 0.3s ease; } @media (max-width: 1200px) { .command-interface { grid-template-columns: 1fr; gap: 20px; } } @media (max-width: 768px) { .command-interface { grid-template-columns: 1fr; } .container { padding: 20px; } .header h1 { font-size: 2em; } } </style> </head> <body> <div class="container"> <div class="header"> <h1>🕳️ BlackHole Core MCP</h1> <p>Model Context Protocol - Intelligent Command Processing</p> </div> <div class="command-interface"> <div class="command-input-section"> <h3>💬 Command Interface</h3> <input type="text" id="commandInput" class="command-input" placeholder="Enter your command in natural language..." onkeypress="handleKeyPress(event)" > <div class="command-buttons"> <button class="btn btn-primary" onclick="processCommand()">Execute Command</button> <button class="btn btn-secondary" onclick="clearResults()">Clear Results</button> <button class="btn btn-info" onclick="showHelp()">Show Help</button> <button class="btn btn-info" onclick="refreshStatus()">Refresh Status</button> </div> <div class="examples"> <h4>💡 Example Commands:</h4> <div class="example-command" onclick="setCommand('search for documents about AI')"> 🔍 search for documents about AI </div> <div class="example-command" onclick="setCommand('get live weather data')"> 🌤️ get live weather data </div> <div class="example-command" onclick="setCommand('find information about machine learning')"> 📚 find information about machine learning </div> <div class="example-command" onclick="setCommand('help')"> ❓ help </div> </div> </div> <div class="status-panel"> <h3>📊 System Status</h3> <div id="systemStatus"> <div class="status-item"> <span>Server</span> <span class="status-indicator" id="serverStatus">Checking...</span> </div> <div class="status-item"> <span>MongoDB</span> <span class="status-indicator" id="mongoStatus">Checking...</span> </div> <div class="status-item"> <span>Archive Agent</span> <span class="status-indicator" id="archiveStatus">Checking...</span> </div> <div class="status-item"> <span>Live Data Agent</span> <span class="status-indicator" id="liveDataStatus">Checking...</span> </div> </div> </div> <div class="file-upload-section"> <h3>📁 File Upload & Processing</h3> <div class="file-drop-zone" id="fileDropZone" onclick="document.getElementById('fileInput').click()"> <div> <p style="font-size: 18px; margin-bottom: 10px;">📁 Drop files here or click to browse</p> <p style="font-size: 14px; opacity: 0.8;">Supports: PDF, Images (PNG, JPG), Text files, Office docs</p> </div> </div> <input type="file" id="fileInput" class="file-input" multiple accept=".pdf,.png,.jpg,.jpeg,.bmp,.tiff,.txt,.doc,.docx,.ppt,.pptx,.xls,.xlsx"> <div id="fileInfo" class="file-info" style="display: none;"> <p><strong>Selected Files:</strong></p> <div id="fileList"></div> </div> <div class="processing-options"> <h4>🔧 Processing Options:</h4> <div class="checkbox-group"> <div class="checkbox-item"> <input type="checkbox" id="enableLLM" checked> <label for="enableLLM">🤖 Enable LLM Analysis (Together.ai)</label> </div> <div class="checkbox-item"> <input type="checkbox" id="saveToDb" checked> <label for="saveToDb">💾 Save to MongoDB</label> </div> <div class="checkbox-item"> <input type="checkbox" id="enableOCR" checked> <label for="enableOCR">👁️ Enable OCR for Images</label> </div> <div class="checkbox-item"> <input type="checkbox" id="generateSummary"> <label for="generateSummary">📝 Generate Summary</label> </div> </div> </div> <div class="command-buttons"> <button class="btn btn-primary" onclick="uploadFiles()" id="uploadBtn" disabled>📤 Upload & Process</button> <button class="btn btn-secondary" onclick="clearFiles()">🗑️ Clear Files</button> <button class="btn btn-info" onclick="showUploadHistory()">📋 Upload History</button> </div> <div class="upload-progress" id="uploadProgress"> <p>Processing files...</p> <div class="progress-bar"> <div class="progress-fill" id="progressFill"></div> </div> <p id="progressText">0%</p> </div> </div> </div> <div class="loading" id="loadingIndicator"> <div class="spinner"></div> <p>Processing command...</p> </div> <div class="results-section"> <h3>📋 Command Results</h3> <div id="resultsContainer"> <p style="text-align: center; opacity: 0.7;">No commands executed yet. Try entering a command above!</p> </div> </div> </div> <script> // Global variables let commandHistory = []; let selectedFiles = []; // Initialize the interface document.addEventListener('DOMContentLoaded', function() { refreshStatus(); initializeFileUpload(); }); function handleKeyPress(event) { if (event.key === 'Enter') { processCommand(); } } function setCommand(command) { document.getElementById('commandInput').value = command; } async function processCommand() { const commandInput = document.getElementById('commandInput'); const command = commandInput.value.trim(); if (!command) { alert('Please enter a command'); return; } showLoading(true); try { const response = await fetch('/api/mcp/command', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ command: command }) }); const result = await response.json(); displayResult(command, result); commandHistory.unshift({ command, result, timestamp: new Date() }); // Clear input commandInput.value = ''; } catch (error) { displayError(command, error.message); } finally { showLoading(false); } } function displayResult(command, result) { const container = document.getElementById('resultsContainer'); // Clear "no commands" message if (container.innerHTML.includes('No commands executed yet')) { container.innerHTML = ''; } const resultElement = document.createElement('div'); resultElement.className = 'result-item'; const timestamp = new Date().toLocaleTimeString(); const status = result.status || 'unknown'; const borderColor = status === 'success' ? '#28a745' : '#dc3545'; resultElement.style.borderLeftColor = borderColor; resultElement.innerHTML = ` <div class="result-header"> <span class="result-command">${command}</span> <span class="result-timestamp">${timestamp}</span> </div> <div class="result-content">${JSON.stringify(result, null, 2)}</div> `; container.insertBefore(resultElement, container.firstChild); } function displayError(command, error) { const result = { status: 'error', error: error, timestamp: new Date().toISOString() }; displayResult(command, result); } async function showHelp() { showLoading(true); try { const response = await fetch('/api/mcp/help'); const helpData = await response.json(); displayResult('help', helpData); } catch (error) { displayError('help', error.message); } finally { showLoading(false); } } async function refreshStatus() { try { // Check server health const healthResponse = await fetch('/api/health'); const healthData = await healthResponse.json(); updateStatusIndicator('serverStatus', healthData.status === 'ok'); updateStatusIndicator('mongoStatus', healthData.mongodb === 'connected'); // Check MCP agent status const mcpResponse = await fetch('/api/mcp/status'); const mcpData = await mcpResponse.json(); updateStatusIndicator('archiveStatus', mcpData.agents?.archive_search?.status === 'available'); updateStatusIndicator('liveDataStatus', mcpData.agents?.live_data?.status === 'available'); } catch (error) { console.error('Error refreshing status:', error); updateStatusIndicator('serverStatus', false); updateStatusIndicator('mongoStatus', false); updateStatusIndicator('archiveStatus', false); updateStatusIndicator('liveDataStatus', false); } } function updateStatusIndicator(elementId, isOnline) { const element = document.getElementById(elementId); if (isOnline) { element.textContent = 'Online'; element.className = 'status-indicator status-online'; } else { element.textContent = 'Offline'; element.className = 'status-indicator status-offline'; } } function showLoading(show) { const loadingIndicator = document.getElementById('loadingIndicator'); loadingIndicator.style.display = show ? 'block' : 'none'; } function clearResults() { const container = document.getElementById('resultsContainer'); container.innerHTML = '<p style="text-align: center; opacity: 0.7;">No commands executed yet. Try entering a command above!</p>'; commandHistory = []; } // File Upload Functions function initializeFileUpload() { const fileInput = document.getElementById('fileInput'); const fileDropZone = document.getElementById('fileDropZone'); // File input change event fileInput.addEventListener('change', handleFileSelect); // Drag and drop events fileDropZone.addEventListener('dragover', handleDragOver); fileDropZone.addEventListener('dragleave', handleDragLeave); fileDropZone.addEventListener('drop', handleFileDrop); } function handleFileSelect(event) { const files = Array.from(event.target.files); updateSelectedFiles(files); } function handleDragOver(event) { event.preventDefault(); event.stopPropagation(); document.getElementById('fileDropZone').classList.add('dragover'); } function handleDragLeave(event) { event.preventDefault(); event.stopPropagation(); document.getElementById('fileDropZone').classList.remove('dragover'); } function handleFileDrop(event) { event.preventDefault(); event.stopPropagation(); document.getElementById('fileDropZone').classList.remove('dragover'); const files = Array.from(event.dataTransfer.files); updateSelectedFiles(files); } function updateSelectedFiles(files) { selectedFiles = files; const fileInfo = document.getElementById('fileInfo'); const fileList = document.getElementById('fileList'); const uploadBtn = document.getElementById('uploadBtn'); if (files.length > 0) { fileInfo.style.display = 'block'; uploadBtn.disabled = false; fileList.innerHTML = ''; files.forEach((file, index) => { const fileItem = document.createElement('div'); fileItem.style.cssText = 'margin: 5px 0; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 5px; display: flex; justify-content: space-between; align-items: center;'; const fileIcon = getFileIcon(file.name); const fileSize = formatFileSize(file.size); fileItem.innerHTML = ` <span>${fileIcon} ${file.name} (${fileSize})</span> <button onclick="removeFile(${index})" style="background: #dc3545; border: none; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;">✕</button> `; fileList.appendChild(fileItem); }); } else { fileInfo.style.display = 'none'; uploadBtn.disabled = true; } } function removeFile(index) { selectedFiles.splice(index, 1); updateSelectedFiles(selectedFiles); } function clearFiles() { selectedFiles = []; document.getElementById('fileInput').value = ''; updateSelectedFiles([]); } function getFileIcon(filename) { const ext = filename.split('.').pop().toLowerCase(); const icons = { 'pdf': '📄', 'png': '🖼️', 'jpg': '🖼️', 'jpeg': '🖼️', 'bmp': '🖼️', 'tiff': '🖼️', 'txt': '📝', 'md': '📝', 'doc': '📘', 'docx': '📘', 'ppt': '📊', 'pptx': '📊', 'xls': '📗', 'xlsx': '📗' }; return icons[ext] || '📎'; } function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } async function uploadFiles() { if (selectedFiles.length === 0) { alert('Please select files to upload'); return; } const uploadProgress = document.getElementById('uploadProgress'); const progressFill = document.getElementById('progressFill'); const progressText = document.getElementById('progressText'); const uploadBtn = document.getElementById('uploadBtn'); // Show progress uploadProgress.style.display = 'block'; uploadBtn.disabled = true; // Get processing options const enableLLM = document.getElementById('enableLLM').checked; const saveToDb = document.getElementById('saveToDb').checked; const enableOCR = document.getElementById('enableOCR').checked; const generateSummary = document.getElementById('generateSummary').checked; try { for (let i = 0; i < selectedFiles.length; i++) { const file = selectedFiles[i]; const progress = ((i + 1) / selectedFiles.length) * 100; // Update progress progressFill.style.width = progress + '%'; progressText.textContent = `Processing ${file.name}... (${Math.round(progress)}%)`; // Create form data const formData = new FormData(); formData.append('file', file); formData.append('enable_llm', enableLLM); formData.append('save_to_db', saveToDb); formData.append('enable_ocr', enableOCR); formData.append('generate_summary', generateSummary); // Upload file const response = await fetch('/api/process-document', { method: 'POST', body: formData }); const result = await response.json(); // Display result const command = `📁 Uploaded: ${file.name}`; displayResult(command, { status: response.ok ? 'success' : 'error', filename: file.name, fileSize: formatFileSize(file.size), processingOptions: { llm: enableLLM, saveToDb: saveToDb, ocr: enableOCR, summary: generateSummary }, result: result, timestamp: new Date().toISOString() }); } // Complete progressText.textContent = 'Upload complete!'; setTimeout(() => { uploadProgress.style.display = 'none'; clearFiles(); }, 2000); } catch (error) { displayError('File Upload', error.message); uploadProgress.style.display = 'none'; } finally { uploadBtn.disabled = false; } } async function showUploadHistory() { showLoading(true); try { const response = await fetch('/api/results'); const results = await response.json(); // Filter for uploaded files const uploadResults = results.filter(r => r.filename); displayResult('📋 Upload History', { status: 'success', totalUploads: uploadResults.length, recentUploads: uploadResults.slice(0, 10).map(r => ({ filename: r.filename, timestamp: r.timestamp, llmEnabled: r.llm_enabled || false })), timestamp: new Date().toISOString() }); } catch (error) { displayError('Upload History', error.message); } finally { showLoading(false); } } </script> </body> </html>

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Nisarg-123-web/MCP2'

If you have feedback or need assistance with the MCP directory API, please join our Discord server