database-form.ts•9.96 kB
export interface DatabaseCredentials {
connectionName: string;
user: string;
password: string;
host: string;
port: number;
database: string;
mfaType?: string;
}
export function renderDatabaseCredentialsForm(request: Request, _: any) {
const formHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Database Connection - Database MCP</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 12px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
padding: 40px;
max-width: 500px;
width: 100%;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
width: 60px;
height: 60px;
background: linear-gradient(135deg, #4CAF50, #45a049);
border-radius: 12px;
margin: 0 auto 20px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
font-weight: bold;
}
h1 {
color: #333;
font-size: 24px;
margin-bottom: 8px;
}
.subtitle {
color: #666;
font-size: 14px;
line-height: 1.5;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 6px;
color: #333;
font-weight: 500;
font-size: 14px;
}
.required {
color: #e74c3c;
}
input, select {
width: 100%;
padding: 12px 16px;
border: 2px solid #e1e8ed;
border-radius: 8px;
font-size: 14px;
transition: border-color 0.2s;
background: white;
}
input:focus, select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.form-row {
display: flex;
gap: 15px;
}
.form-row .form-group {
flex: 1;
}
.info-box {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 16px;
margin-bottom: 20px;
font-size: 13px;
color: #666;
}
.info-box strong {
color: #333;
}
.submit-btn {
width: 100%;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 14px 20px;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.submit-btn:hover {
transform: translateY(-1px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.security-note {
margin-top: 20px;
padding: 12px;
background: #e8f5e8;
border-left: 4px solid #4CAF50;
border-radius: 4px;
font-size: 12px;
color: #2e7d32;
}
.example-formats {
font-size: 12px;
color: #888;
margin-top: 4px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">DB</div>
<h1>Connect Your Database</h1>
<p class="subtitle">
Provide your database credentials to enable AI access to your PostgreSQL or Supabase database.
</p>
</div>
<div class="info-box">
<strong>Supported Databases:</strong> PostgreSQL, Supabase<br>
<strong>Security:</strong> Your credentials are encrypted and only used for your session.
</div>
<form method="POST" action="/connect">
<div class="form-group">
<label for="connectionName">
Connection Name <span class="required">*</span>
</label>
<input
type="text"
id="connectionName"
name="connectionName"
placeholder="My Database Connection"
required
>
</div>
<div class="form-row">
<div class="form-group">
<label for="host">
Host <span class="required">*</span>
</label>
<input
type="text"
id="host"
name="host"
placeholder="localhost or db.xxx.supabase.co"
required
>
<div class="example-formats">
Examples: localhost, db.abcdefg.supabase.co
</div>
</div>
<div class="form-group">
<label for="port">
Port <span class="required">*</span>
</label>
<input
type="number"
id="port"
name="port"
placeholder="5432"
value="5432"
required
>
</div>
</div>
<div class="form-group">
<label for="database">
Database <span class="required">*</span>
</label>
<input
type="text"
id="database"
name="database"
placeholder="postgres"
required
>
<div class="example-formats">
Usually "postgres" for Supabase
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="user">
Username <span class="required">*</span>
</label>
<input
type="text"
id="user"
name="user"
placeholder="postgres"
required
>
</div>
<div class="form-group">
<label for="password">
Password <span class="required">*</span>
</label>
<input
type="password"
id="password"
name="password"
placeholder="Your database password"
required
>
</div>
</div>
<div class="form-group">
<label for="mfaType">
MFA Type
</label>
<select id="mfaType" name="mfaType">
<option value="">None</option>
<option value="totp">TOTP (Time-based)</option>
<option value="sms">SMS</option>
<option value="email">Email</option>
</select>
</div>
<button type="submit" class="submit-btn">
Connect Database
</button>
<div class="security-note">
🔒 Your database credentials are encrypted and stored securely. They are only used to establish your database connection and are not shared with third parties.
</div>
</form>
</div>
</body>
</html>`;
return new Response(formHtml, {
headers: { "Content-Type": "text/html" },
});
}
export function parseDatabaseCredentials(formData: FormData): DatabaseCredentials {
return {
connectionName: formData.get("connectionName") as string,
user: formData.get("user") as string,
password: formData.get("password") as string,
host: formData.get("host") as string,
port: parseInt(formData.get("port") as string) || 5432,
database: formData.get("database") as string,
mfaType: formData.get("mfaType") as string || undefined,
};
}
export function validateDatabaseCredentials(creds: DatabaseCredentials): string[] {
const errors: string[] = [];
if (!creds.connectionName?.trim()) {
errors.push("Connection name is required");
}
if (!creds.host?.trim()) {
errors.push("Host is required");
}
if (!creds.user?.trim()) {
errors.push("Username is required");
}
if (!creds.password?.trim()) {
errors.push("Password is required");
}
if (!creds.database?.trim()) {
errors.push("Database name is required");
}
if (creds.port < 1 || creds.port > 65535) {
errors.push("Port must be between 1 and 65535");
}
return errors;
}