<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Umbrella MCP Authentication Portal</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
max-width: 500px;
width: 100%;
padding: 40px;
}
h1 {
color: #333;
margin-bottom: 10px;
font-size: 28px;
}
.subtitle {
color: #666;
margin-bottom: 30px;
font-size: 14px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
color: #555;
font-weight: 500;
}
input {
width: 100%;
padding: 12px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 16px;
transition: border-color 0.3s;
}
input:focus {
outline: none;
border-color: #667eea;
}
button {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s;
}
button:hover {
transform: translateY(-2px);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.error {
background: #fee;
color: #c33;
padding: 12px;
border-radius: 8px;
margin-bottom: 20px;
display: none;
}
.success {
background: #e8f5e9;
border: 2px solid #4caf50;
padding: 20px;
border-radius: 8px;
margin-top: 20px;
display: none;
}
.success h3 {
color: #2e7d32;
margin-bottom: 15px;
}
.config-box {
background: #f5f5f5;
padding: 15px;
border-radius: 8px;
margin: 15px 0;
font-family: 'Courier New', monospace;
font-size: 12px;
white-space: pre-wrap;
word-break: break-all;
max-height: 200px;
overflow-y: auto;
}
.copy-btn {
background: #4caf50;
padding: 8px 16px;
font-size: 14px;
margin-top: 10px;
}
.instructions {
color: #555;
font-size: 14px;
line-height: 1.6;
}
.instructions ol {
margin-left: 20px;
margin-top: 10px;
}
.session-info {
background: #fff3cd;
border: 1px solid #ffc107;
padding: 10px;
border-radius: 8px;
margin-top: 15px;
font-size: 14px;
color: #856404;
}
.server-status {
text-align: center;
padding: 10px;
background: #f0f0f0;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
}
.status-online {
color: #4caf50;
}
.status-offline {
color: #f44336;
}
</style>
</head>
<body>
<div class="container">
<div class="server-status" id="serverStatus">
Checking server status...
</div>
<h1>🔐 Umbrella MCP Portal</h1>
<p class="subtitle">Authenticate to get your Claude Desktop configuration</p>
<div class="error" id="error"></div>
<form id="authForm">
<div class="form-group">
<label for="username">Email / Username</label>
<input
type="text"
id="username"
name="username"
placeholder="your-email@domain.com"
required
>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
type="password"
id="password"
name="password"
placeholder="Your password"
required
>
</div>
<button type="submit" id="submitBtn">Authenticate</button>
</form>
<div class="success" id="success">
<h3>✅ Authentication Successful!</h3>
<div class="instructions">
<strong>Your Session Token:</strong>
<div class="config-box" id="sessionToken"></div>
<button class="copy-btn" onclick="copyToken()">📋 Copy Token</button>
</div>
<div class="instructions" style="margin-top: 20px;">
<strong>Claude Desktop Configuration:</strong>
<div class="config-box" id="claudeConfig"></div>
<button class="copy-btn" onclick="copyConfig()">📋 Copy Configuration</button>
</div>
<div class="instructions" style="margin-top: 20px;">
<strong>How to use:</strong>
<ol>
<li>Copy the configuration above</li>
<li>Open Claude Desktop Settings</li>
<li>Go to Developer → Edit Config</li>
<li>Add the configuration to your MCP servers</li>
<li>Restart Claude Desktop</li>
</ol>
</div>
<div class="session-info">
⏱️ Session expires in 30 minutes of inactivity
</div>
</div>
</div>
<script>
const SERVER_URL = 'http://localhost:3000';
let currentToken = '';
let currentConfig = '';
// Check server status
async function checkServerStatus() {
try {
const response = await fetch(`${SERVER_URL}/health`);
if (response.ok) {
const data = await response.json();
document.getElementById('serverStatus').innerHTML =
`<span class="status-online">✅ Server Online | ${data.activeSessions || 0} active sessions</span>`;
} else {
document.getElementById('serverStatus').innerHTML =
`<span class="status-offline">❌ Server Offline</span>`;
}
} catch (error) {
document.getElementById('serverStatus').innerHTML =
`<span class="status-offline">❌ Cannot connect to server at ${SERVER_URL}</span>`;
}
}
// Check status on load
checkServerStatus();
setInterval(checkServerStatus, 10000);
// Handle form submission
document.getElementById('authForm').addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const submitBtn = document.getElementById('submitBtn');
const errorDiv = document.getElementById('error');
const successDiv = document.getElementById('success');
// Reset displays
errorDiv.style.display = 'none';
successDiv.style.display = 'none';
// Disable button
submitBtn.disabled = true;
submitBtn.textContent = 'Authenticating...';
try {
const response = await fetch(`${SERVER_URL}/auth`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (response.ok && data.success) {
// Show success
currentToken = data.sessionToken;
currentConfig = JSON.stringify({
"mcpServers": {
"umbrella-cost": {
"command": "npx",
"args": [
"mcp-remote",
`${SERVER_URL}/sse?token=${data.sessionToken}`
]
}
}
}, null, 2);
document.getElementById('sessionToken').textContent = currentToken;
document.getElementById('claudeConfig').textContent = currentConfig;
successDiv.style.display = 'block';
// Clear form
document.getElementById('authForm').reset();
} else {
// Show error
errorDiv.textContent = data.error || 'Authentication failed';
errorDiv.style.display = 'block';
}
} catch (error) {
errorDiv.textContent = `Connection error: ${error.message}`;
errorDiv.style.display = 'block';
} finally {
submitBtn.disabled = false;
submitBtn.textContent = 'Authenticate';
}
});
// Copy functions
function copyToken() {
navigator.clipboard.writeText(currentToken);
alert('Session token copied to clipboard!');
}
function copyConfig() {
navigator.clipboard.writeText(currentConfig);
alert('Configuration copied to clipboard!');
}
</script>
</body>
</html>