Skip to main content
Glama

Fabric MCP Agent

by yingkiat
test_ui.html41.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Fabric MCP Agent - Test UI</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%); min-height: 100vh; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; background: white; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); overflow: hidden; } .header { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 30px; text-align: center; } .header h1 { font-size: 2.5em; margin-bottom: 10px; } .header p { font-size: 1.1em; opacity: 0.9; } .content { padding: 30px; } .test-section { margin-bottom: 40px; background: #f8f9fa; border-radius: 10px; padding: 25px; border-left: 5px solid #4facfe; } .test-section h2 { color: #333; margin-bottom: 20px; font-size: 1.5em; } .input-group { margin-bottom: 20px; } .input-group label { display: block; margin-bottom: 8px; font-weight: 600; color: #555; } .input-group input, .input-group textarea, .input-group select { width: 100%; padding: 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 14px; transition: border-color 0.3s; } .input-group input:focus, .input-group textarea:focus, .input-group select:focus { outline: none; border-color: #4facfe; } .btn { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; border: none; padding: 12px 25px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 600; transition: transform 0.2s; } .btn:hover { transform: translateY(-2px); } .btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } .response { margin-top: 20px; padding: 20px; background: white; border-radius: 8px; border: 1px solid #e0e0e0; max-height: 400px; overflow-y: auto; } .response pre { white-space: pre-wrap; font-family: 'Courier New', monospace; font-size: 12px; line-height: 1.4; } .loading { display: none; color: #666; font-style: italic; } .error { color: #e74c3c; background: #fdf2f2; border: 1px solid #f5c6cb; } .success { color: #27ae60; background: #f2fff2; border: 1px solid #c3e6cb; } .quick-tests { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 20px; } .quick-test-btn { background: #e9ecef; color: #333; border: 2px solid #e9ecef; padding: 10px 15px; border-radius: 8px; cursor: pointer; font-size: 13px; transition: all 0.3s; } .quick-test-btn:hover { background: #4facfe; color: white; border-color: #4facfe; } /* Tab Navigation Styles */ .tab-navigation { background: #f8f9fa; border-bottom: 2px solid #e9ecef; padding: 0 30px; display: flex; gap: 0; } .tab-button { background: transparent; border: none; padding: 15px 25px; cursor: pointer; font-size: 14px; font-weight: 600; color: #666; border-bottom: 3px solid transparent; transition: all 0.3s ease; } .tab-button:hover { color: #4facfe; background: rgba(79, 172, 254, 0.1); } .tab-button.active { color: #4facfe; border-bottom-color: #4facfe; background: white; } .tab-content { display: none; } .tab-content.active { display: block; } /* Prompt Editor Styles */ .prompt-editor { display: grid; grid-template-columns: 250px 1fr; gap: 20px; height: 600px; } .prompt-list { background: #f8f9fa; border-radius: 8px; padding: 15px; overflow-y: auto; } .prompt-item { padding: 10px 15px; margin-bottom: 5px; background: white; border-radius: 6px; cursor: pointer; transition: all 0.2s; border: 1px solid #e0e0e0; } .prompt-item:hover { background: #4facfe; color: white; } .prompt-item.selected { background: #4facfe; color: white; } .prompt-editor-panel { display: flex; flex-direction: column; gap: 15px; } .prompt-editor-header { display: flex; justify-content: space-between; align-items: center; padding: 15px; background: #f8f9fa; border-radius: 8px; } .prompt-editor-textarea { flex: 1; min-height: 400px; font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 13px; line-height: 1.5; resize: none; } .prompt-actions { display: flex; gap: 10px; align-items: center; } .btn-secondary { background: #6c757d; color: white; } .btn-success { background: #28a745; color: white; } .btn-small { padding: 8px 16px; font-size: 12px; } .endpoint-info { background: #e3f2fd; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #2196f3; } .endpoint-info code { background: #fff; padding: 2px 6px; border-radius: 4px; font-family: 'Courier New', monospace; } .sql-results-table { margin-top: 15px; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .sql-results-table table { width: 100%; border-collapse: collapse; } .sql-results-table th { background: #4facfe; color: white; padding: 12px 8px; text-align: left; font-weight: 600; font-size: 13px; } .sql-results-table td { padding: 10px 8px; border-bottom: 1px solid #e0e0e0; font-size: 13px; } .sql-results-table tr:nth-child(even) { background: #f8f9fa; } .sql-results-table tr:hover { background: #e3f2fd; } .no-results { text-align: center; color: #666; font-style: italic; padding: 20px; } </style> </head> <body> <div class="container"> <div class="header"> <h1>🔷 Fabric MCP Agent</h1> <p>Test UI for Microsoft Fabric Data Warehouse MCP Server with Agentic Intelligence</p> </div> <!-- Tab Navigation --> <div class="tab-navigation"> <button class="tab-button active" onclick="switchTab(event, 'agentic-tab')">🧠 Agentic Intelligence</button> <button class="tab-button" onclick="switchTab(event, 'tools-tab')">🔧 MCP Tools</button> <button class="tab-button" onclick="switchTab(event, 'prompts-tab')">📝 Prompt Management</button> </div> <div class="content"> <!-- Agentic Intelligence Tab --> <div id="agentic-tab" class="tab-content active"> <div class="test-section"> <h2>🧠 Agentic Intelligence (Recommended)</h2> <div class="endpoint-info"> <strong>Endpoint:</strong> <code>POST /mcp</code><br> Uses intent classification, prompt modules, and tool chaining for enriched responses. </div> <div class="input-group"> <label for="agenticQuestion">Ask a business question:</label> <textarea id="agenticQuestion" rows="3" placeholder="tell me the components in MRH-011C"></textarea> </div> <button class="btn" onclick="testAgentic()">🚀 Ask with AI Reasoning</button> <div class="loading" id="agenticLoading">Processing with agentic intelligence...</div> <div class="quick-tests"> <button class="quick-test-btn" onclick="setAgenticQuestion('Hogy quoted us a surgical kit with BD Luer-Lock Syringe 2.5mL. What\'s our equivalent?')">Complex AI Query (Fallback)</button> <button class="quick-test-btn" onclick="setAgenticQuestion('what\'s our product for hogy BR-56U10')">Direct Tool Query</button> <button class="quick-test-btn" onclick="setAgenticQuestion('Show me all products like MRH-011C')">Similar Products</button> <button class="quick-test-btn" onclick="setAgenticQuestion('What product types are available?')">Product Types</button> </div> <div class="response" id="agenticResponse"></div> <!-- SQL Results Table --> <div id="sqlResultsTable" style="display: none; margin-top: 20px;"> <h3>📊 Query Results</h3> <div id="resultsContainer"></div> </div> </div> </div> <!-- MCP Tools Tab --> <div id="tools-tab" class="tab-content"> <div class="test-section"> <h2>🔧 Direct MCP Tool Testing</h2> <div class="endpoint-info"> <strong>Endpoint:</strong> <code>POST /call_tool</code><br> Direct access to individual MCP tools for debugging and testing. Advanced users can pass custom parameters. </div> <div class="input-group"> <label for="toolSelect2">Select Tool:</label> <select id="toolSelect2" onchange="updateToolForm()"> <option value="run_sql_query">run_sql_query</option> <option value="get_metadata">get_metadata</option> <option value="summarize_results">summarize_results</option> <option value="generate_visualization">generate_visualization</option> </select> </div> <div id="toolArgsForm"> <!-- Dynamic form based on selected tool --> </div> <button class="btn" onclick="testTool()" id="toolButton">Execute Tool</button> <div class="loading" id="toolLoading">Executing tool...</div> <div class="response" id="toolResponse"></div> </div> <!-- Schema Discovery --> <div class="test-section"> <h2>📊 Schema Discovery</h2> <div class="endpoint-info"> <strong>Endpoint:</strong> <code>GET /list_tools</code><br> Discover all available MCP tools and their schemas. </div> <button class="btn" onclick="listTools()">📋 List Available Tools</button> <div class="loading" id="schemaLoading">Loading tools...</div> <div class="response" id="schemaResponse"></div> </div> </div> <!-- Prompt Management Tab --> <div id="prompts-tab" class="tab-content"> <div class="test-section"> <h2>📝 Prompt Module Management</h2> <div class="endpoint-info"> <strong>Business User Control:</strong> Edit prompt modules to customize AI behavior for your domain expertise.<br> Changes are automatically backed up and take effect immediately. </div> <div class="prompt-editor"> <div class="prompt-list"> <h3 style="margin-bottom: 15px; color: #333;">Available Prompts</h3> <div id="promptList"> <div class="loading">Loading prompts...</div> </div> </div> <div class="prompt-editor-panel"> <div class="prompt-editor-header"> <div> <h3 id="currentPromptName">Select a prompt to edit</h3> <small id="currentPromptInfo" style="color: #666;"></small> </div> <div class="prompt-actions"> <button class="btn btn-secondary btn-small" onclick="viewBackups()">📋 View Backups</button> <button class="btn btn-success btn-small" onclick="savePrompt()" id="savePromptBtn" disabled>💾 Save Changes</button> </div> </div> <textarea id="promptEditor" class="prompt-editor-textarea input-group" placeholder="Select a prompt module from the left to begin editing..." disabled ></textarea> <div id="promptSaveStatus" class="response" style="display: none;"></div> </div> </div> </div> </div> </div> </div> <script> const API_BASE = 'http://localhost:8000'; const SUBSCRIPTION_KEY = '2c405c6d95ea493985aeda1985e91bf7'; // Replace with your actual key // Agentic Intelligence Test async function testAgentic() { const question = document.getElementById('agenticQuestion').value; if (!question.trim()) { alert('Please enter a question'); return; } showLoading('agenticLoading', true); clearResponse('agenticResponse'); try { const response = await fetch(`${API_BASE}/mcp`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY }, body: JSON.stringify({ question }) }); const result = await response.json(); showResponse('agenticResponse', result, response.ok); // Parse and display results based on execution strategy if (result.tool_chain_results && result.tool_chain_results.stage3_evaluation) { displayAgenticResults(result); } else if (result.tool_chain_results && result.tool_chain_results.run_sql_query) { displaySQLResults(result.tool_chain_results.run_sql_query.results); } } catch (error) { showResponse('agenticResponse', { error: error.message }, false); } finally { showLoading('agenticLoading', false); } } function setAgenticQuestion(question) { document.getElementById('agenticQuestion').value = question; } // MCP Tool Test async function testTool() { const tool = document.getElementById('toolSelect2').value; const args = collectToolArgs(); showLoading('toolLoading', true); clearResponse('toolResponse'); try { const response = await fetch(`${API_BASE}/call_tool`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY }, body: JSON.stringify({ tool, args }) }); const result = await response.json(); showResponse('toolResponse', result, response.ok); } catch (error) { showResponse('toolResponse', { error: error.message }, false); } finally { showLoading('toolLoading', false); } } function updateToolForm() { const tool = document.getElementById('toolSelect2').value; const formContainer = document.getElementById('toolArgsForm'); let formHTML = ''; switch (tool) { case 'run_sql_query': formHTML = ` <div class="input-group"> <label>Question (natural language):</label> <textarea id="sqlQuestion" rows="3" placeholder="What are the components in MRH-011C?"></textarea> <small style="color: #666;">Enter a natural language question to convert to SQL</small> </div> <div style="text-align: center; margin: 10px 0; color: #999; font-weight: bold;">— OR —</div> <div class="input-group"> <label>Direct SQL:</label> <textarea id="directSQL" rows="3" placeholder="SELECT pt.part_number, pt.description FROM JPNPROdb_pt_mstr pt JOIN JPNPROdb_ps_mstr ps ON pt.product_id = ps.product_id WHERE ps.product_code = 'MRH-011C'"></textarea> <small style="color: #666;">Enter raw SQL to execute directly</small> </div> `; break; case 'get_metadata': formHTML = ` <div class="input-group"> <label>Table Name (optional):</label> <input type="text" id="tableName" placeholder="JPNPROdb_ps_mstr"> </div> `; break; case 'summarize_results': formHTML = ` <div class="input-group"> <label>Data (JSON array):</label> <textarea id="dataToSummarize" rows="3" placeholder='[{"product": "A", "count": 10}]'></textarea> </div> <div class="input-group"> <label>Context:</label> <input type="text" id="summaryContext" placeholder="product_planning"> </div> `; break; case 'generate_visualization': formHTML = ` <div class="input-group"> <label>Data (JSON array):</label> <textarea id="vizData" rows="3" placeholder='[{"category": "A", "value": 10}]'></textarea> </div> <div class="input-group"> <label>Chart Type:</label> <select id="chartType"> <option value="table">Table</option> <option value="bar">Bar Chart</option> <option value="line">Line Chart</option> <option value="pie">Pie Chart</option> </select> </div> <div class="input-group"> <label>Title:</label> <input type="text" id="chartTitle" placeholder="Product Analysis"> </div> `; break; } formContainer.innerHTML = formHTML; } function collectToolArgs() { const tool = document.getElementById('toolSelect2').value; const args = {}; switch (tool) { case 'run_sql_query': const question = document.getElementById('sqlQuestion').value; const sql = document.getElementById('directSQL').value; if (question.trim()) args.question = question; if (sql.trim()) args.sql = sql; break; case 'get_metadata': const tableName = document.getElementById('tableName').value; if (tableName.trim()) args.table_name = tableName; break; case 'summarize_results': const data = document.getElementById('dataToSummarize').value; const context = document.getElementById('summaryContext').value; try { args.data = JSON.parse(data || '[]'); } catch (e) { args.data = []; } if (context.trim()) args.context = context; break; case 'generate_visualization': const vizData = document.getElementById('vizData').value; const chartType = document.getElementById('chartType').value; const title = document.getElementById('chartTitle').value; try { args.data = JSON.parse(vizData || '[]'); } catch (e) { args.data = []; } if (chartType) args.chart_type = chartType; if (title.trim()) args.title = title; break; } return args; } // Schema Discovery async function listTools() { showLoading('schemaLoading', true); clearResponse('schemaResponse'); try { const response = await fetch(`${API_BASE}/list_tools`, { headers: { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY } }); const result = await response.json(); showResponse('schemaResponse', result, response.ok); } catch (error) { showResponse('schemaResponse', { error: error.message }, false); } finally { showLoading('schemaLoading', false); } } // Utility Functions function showLoading(elementId, show) { document.getElementById(elementId).style.display = show ? 'block' : 'none'; } function clearResponse(elementId) { const element = document.getElementById(elementId); element.innerHTML = ''; element.className = 'response'; } function showResponse(elementId, data, success) { const element = document.getElementById(elementId); element.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`; element.className = `response ${success ? 'success' : 'error'}`; } function displayAgenticResults(result) { const tableContainer = document.getElementById('sqlResultsTable'); const resultsContainer = document.getElementById('resultsContainer'); // Clear previous results resultsContainer.innerHTML = ''; let html = ''; // Display Stage 3 Business Analysis if available if (result.tool_chain_results && result.tool_chain_results.stage3_evaluation) { const stage3 = result.tool_chain_results.stage3_evaluation; html += ` <div class="stage3-analysis" style="margin-bottom: 30px; padding: 20px; background: #f0f8ff; border-radius: 10px; border-left: 5px solid #4facfe;"> <h3 style="color: #333; margin-bottom: 15px;">🎯 Business Analysis</h3> <div style="margin-bottom: 20px;"> <h4 style="color: #4facfe; margin-bottom: 10px;">Answer:</h4> <p style="font-size: 16px; line-height: 1.6; color: #333;">${stage3.business_answer}</p> </div> <div style="margin-bottom: 20px;"> <h4 style="color: #4facfe; margin-bottom: 10px;">Key Findings:</h4> <ul style="padding-left: 20px;"> ${stage3.key_findings.map(finding => `<li style="margin-bottom: 8px; color: #555;">${finding}</li>`).join('')} </ul> </div> <div style="margin-bottom: 20px;"> <h4 style="color: #4facfe; margin-bottom: 10px;">Recommended Action:</h4> <p style="font-style: italic; color: #666; background: #fff; padding: 10px; border-radius: 5px;">${stage3.recommended_action}</p> </div> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 15px;"> <div> <strong style="color: #4facfe;">Confidence:</strong> <span style="padding: 3px 8px; background: ${stage3.supporting_data.confidence === 'high' ? '#28a745' : stage3.supporting_data.confidence === 'medium' ? '#ffc107' : '#dc3545'}; color: white; border-radius: 3px; font-size: 12px;">${stage3.supporting_data.confidence}</span> </div> <div> <strong style="color: #4facfe;">Data Quality:</strong> <span style="color: #666;">${stage3.data_quality}</span> </div> </div> </div> `; } // Display detailed SQL results if available if (result.tool_chain_results && result.tool_chain_results.stage2_query && result.tool_chain_results.stage2_query.results) { const sqlResults = result.tool_chain_results.stage2_query.results; html += '<h3 style="color: #333; margin-bottom: 15px;">📊 Detailed Data</h3>'; html += generateSQLTable(sqlResults); } else if (result.tool_chain_results && result.tool_chain_results.run_sql_query && result.tool_chain_results.run_sql_query.results) { const sqlResults = result.tool_chain_results.run_sql_query.results; html += '<h3 style="color: #333; margin-bottom: 15px;">📊 Query Results</h3>'; html += generateSQLTable(sqlResults); } // Display summary if available if (result.tool_chain_results && result.tool_chain_results.summarize_results) { const summary = result.tool_chain_results.summarize_results; html += ` <div style="margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px;"> <h4 style="color: #333; margin-bottom: 10px;">📋 Data Summary</h4> <p style="color: #666;">${summary.summary}</p> <small style="color: #999;">Records found: ${summary.row_count || 'N/A'}</small> </div> `; } if (html) { resultsContainer.innerHTML = html; tableContainer.style.display = 'block'; } else { resultsContainer.innerHTML = '<div class="no-results">No results to display</div>'; tableContainer.style.display = 'block'; } } function generateSQLTable(results) { if (!results || results.length === 0) { return '<div class="no-results">No data found</div>'; } const keys = Object.keys(results[0]); let tableHTML = ` <div class="sql-results-table"> <table> <thead> <tr> ${keys.map(key => `<th>${key}</th>`).join('')} </tr> </thead> <tbody> ${results.map(row => ` <tr> ${keys.map(key => `<td>${row[key] || ''}</td>`).join('')} </tr> `).join('')} </tbody> </table> </div> `; return tableHTML; } function displaySQLResults(results) { const tableContainer = document.getElementById('sqlResultsTable'); const resultsContainer = document.getElementById('resultsContainer'); if (!results || results.length === 0) { resultsContainer.innerHTML = '<div class="no-results">No results found</div>'; tableContainer.style.display = 'block'; return; } // Create table const table = document.createElement('table'); const thead = document.createElement('thead'); const tbody = document.createElement('tbody'); // Create header row const headerRow = document.createElement('tr'); const keys = Object.keys(results[0]); keys.forEach(key => { const th = document.createElement('th'); th.textContent = key; headerRow.appendChild(th); }); thead.appendChild(headerRow); // Create data rows results.forEach(row => { const tr = document.createElement('tr'); keys.forEach(key => { const td = document.createElement('td'); td.textContent = row[key] || ''; tr.appendChild(td); }); tbody.appendChild(tr); }); table.appendChild(thead); table.appendChild(tbody); resultsContainer.innerHTML = ''; const tableWrapper = document.createElement('div'); tableWrapper.className = 'sql-results-table'; tableWrapper.appendChild(table); resultsContainer.appendChild(tableWrapper); tableContainer.style.display = 'block'; } // Tab Management function switchTab(event, tabName) { // Hide all tab contents const tabContents = document.querySelectorAll('.tab-content'); tabContents.forEach(tab => { tab.classList.remove('active'); }); // Remove active class from all tab buttons const tabButtons = document.querySelectorAll('.tab-button'); tabButtons.forEach(button => { button.classList.remove('active'); }); // Show selected tab and activate button document.getElementById(tabName).classList.add('active'); event.target.classList.add('active'); // Load data for prompt tab if (tabName === 'prompts-tab') { loadPromptList(); } } // Prompt Management Functions let currentPrompt = null; let originalContent = ''; async function loadPromptList() { try { const response = await fetch(`${API_BASE}/prompts`, { headers: { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY } }); const data = await response.json(); const promptList = document.getElementById('promptList'); promptList.innerHTML = ''; data.prompts.forEach(prompt => { const promptItem = document.createElement('div'); promptItem.className = 'prompt-item'; promptItem.textContent = prompt; promptItem.onclick = () => loadPrompt(prompt); promptList.appendChild(promptItem); }); } catch (error) { document.getElementById('promptList').innerHTML = '<div class="error">Error loading prompts: ' + error.message + '</div>'; } } async function loadPrompt(promptName) { try { // Update UI selection document.querySelectorAll('.prompt-item').forEach(item => { item.classList.remove('selected'); }); event.target.classList.add('selected'); const response = await fetch(`${API_BASE}/prompts/${promptName}`, { headers: { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY } }); const data = await response.json(); currentPrompt = promptName; originalContent = data.content; document.getElementById('currentPromptName').textContent = `Editing: ${promptName}`; document.getElementById('currentPromptInfo').textContent = `Last modified: ${new Date(data.last_modified * 1000).toLocaleString()}`; document.getElementById('promptEditor').value = data.content; document.getElementById('promptEditor').disabled = false; document.getElementById('savePromptBtn').disabled = false; // Add change detection document.getElementById('promptEditor').oninput = () => { const hasChanges = document.getElementById('promptEditor').value !== originalContent; document.getElementById('savePromptBtn').textContent = hasChanges ? '💾 Save Changes*' : '💾 Save Changes'; }; } catch (error) { showPromptStatus('Error loading prompt: ' + error.message, 'error'); } } async function savePrompt() { if (!currentPrompt) return; const content = document.getElementById('promptEditor').value; document.getElementById('savePromptBtn').disabled = true; document.getElementById('savePromptBtn').textContent = '⏳ Saving...'; try { const response = await fetch(`${API_BASE}/prompts/${currentPrompt}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY }, body: JSON.stringify({ module_name: currentPrompt, content: content }) }); const result = await response.json(); if (response.ok) { originalContent = content; showPromptStatus(result.message, 'success'); if (result.backup_created) { showPromptStatus(result.message + ` (Backup: ${result.backup_created})`, 'success'); } } else { showPromptStatus('Error: ' + result.detail, 'error'); } } catch (error) { showPromptStatus('Network error: ' + error.message, 'error'); } finally { document.getElementById('savePromptBtn').disabled = false; document.getElementById('savePromptBtn').textContent = '💾 Save Changes'; } } async function viewBackups() { if (!currentPrompt) return; try { const response = await fetch(`${API_BASE}/prompts/${currentPrompt}/backups`, { headers: { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY } }); const data = await response.json(); if (data.backups.length === 0) { showPromptStatus('No backups found for this prompt.', 'success'); } else { let backupList = `Found ${data.backups.length} backups:\n\n`; data.backups.forEach(backup => { backupList += `📄 ${backup.filename} (${new Date(backup.timestamp * 1000).toLocaleString()}) - ${backup.size} bytes\n`; }); showPromptStatus(backupList, 'success'); } } catch (error) { showPromptStatus('Error loading backups: ' + error.message, 'error'); } } function showPromptStatus(message, type = 'success') { const statusDiv = document.getElementById('promptSaveStatus'); statusDiv.className = `response ${type}`; statusDiv.innerHTML = `<pre>${message}</pre>`; statusDiv.style.display = 'block'; // Auto-hide after 5 seconds setTimeout(() => { statusDiv.style.display = 'none'; }, 5000); } // Initialize document.addEventListener('DOMContentLoaded', function() { updateToolForm(); }); </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/yingkiat/mcp_fabric_server'

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