Skip to main content
Glama
approvalDialog.ts5.33 kB
import { type ClientInfo } from '@cloudflare/workers-oauth-provider' import { type ValidatedEnv } from '../../../types/env' import { APPROVAL_CONFIG } from './config' /** * Configuration for the approval dialog */ interface ApprovalDialogOptions { /** * Client information for basic display */ client: ClientInfo | null /** * Server information */ server: { name: string logo?: string } /** * State data to encode in the approval flow */ state: Record<string, any> /** * Validated environment configuration */ config: ValidatedEnv } /** * Renders an approval page that redirects to Schwab OAuth * Following Cloudflare's pattern of minimal custom UI * * @param request - The HTTP request * @param options - Configuration for the approval * @returns A Response containing HTML with auto-redirect */ export function renderApprovalDialog( request: Request, options: ApprovalDialogOptions, ): Response { const { client, server, state } = options // Encode state for the redirect const encodedState = btoa(JSON.stringify(state)) const htmlContent = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Authorizing ${client?.clientName || 'MCP Client'}</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; padding: 0; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; } .container { background: white; border-radius: 12px; padding: 2rem; box-shadow: 0 10px 40px rgba(0,0,0,0.1); text-align: center; max-width: 400px; width: 90%; } .logo { width: 64px; height: 64px; margin: 0 auto 1rem; border-radius: 12px; } h1 { margin: 0 0 1rem 0; color: #333; font-size: 1.5rem; font-weight: 600; } p { color: #666; margin: 0 0 2rem 0; line-height: 1.5; } .btn { background: #0070f3; color: white; border: none; padding: 1rem 2rem; border-radius: 8px; font-size: 1rem; font-weight: 500; cursor: pointer; width: 100%; transition: background 0.2s; } .btn:hover { background: #0051cc; } .spinner { display: none; width: 20px; height: 20px; border: 2px solid #ffffff40; border-top: 2px solid #ffffff; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .auto-redirect { color: #888; font-size: 0.9rem; margin-top: 1rem; } </style> </head> <body> <div class="container"> ${server.logo ? `<img src="${server.logo}" alt="${server.name}" class="logo">` : ''} <h1>Connect to ${server.name}</h1> <p><strong>${client?.clientName || 'An MCP Client'}</strong> wants to access your Schwab account through ${server.name}.</p> <form method="post" action="${new URL(request.url).pathname}" id="approvalForm"> <input type="hidden" name="state" value="${encodedState}"> <button type="submit" class="btn" id="approveBtn"> <span id="btnText">Continue to Schwab</span> <div class="spinner" id="spinner"></div> </button> </form> <p class="auto-redirect">Redirecting automatically in <span id="countdown">3</span> seconds...</p> </div> <script> // Auto-submit after countdown let countdown = ${APPROVAL_CONFIG.COUNTDOWN_SECONDS}; const countdownEl = document.getElementById('countdown'); const form = document.getElementById('approvalForm'); const btn = document.getElementById('approveBtn'); const btnText = document.getElementById('btnText'); const spinner = document.getElementById('spinner'); const timer = setInterval(() => { countdown--; countdownEl.textContent = countdown; if (countdown <= 0) { clearInterval(timer); submitForm(); } }, 1000); // Handle manual click form.addEventListener('submit', (e) => { e.preventDefault(); clearInterval(timer); submitForm(); }); function submitForm() { btnText.style.display = 'none'; spinner.style.display = 'block'; btn.disabled = true; form.submit(); } </script> </body> </html> ` return new Response(htmlContent, { headers: { 'Content-Type': 'text/html; charset=utf-8', 'Content-Security-Policy': "default-src 'self' 'unsafe-inline'; img-src https: data:;", }, }) }

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/sudowealth/schwab-mcp'

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