Skip to main content
Glama

DBeaver MCP Server

by srthkdev
utils.ts10.9 kB
import fs from 'fs'; import path from 'path'; import os from 'os'; /** * Find DBeaver executable path across different platforms */ export function findDBeaverExecutable(): string { const platform = os.platform(); const possiblePaths: string[] = []; if (platform === 'win32') { possiblePaths.push( 'C:\\Program Files\\DBeaver\\dbeaver.exe', 'C:\\Program Files (x86)\\DBeaver\\dbeaver.exe', path.join(os.homedir(), 'AppData', 'Local', 'DBeaver', 'dbeaver.exe'), path.join(os.homedir(), 'scoop', 'apps', 'dbeaver', 'current', 'dbeaver.exe'), 'dbeaver.exe' // fallback to PATH ); } else if (platform === 'darwin') { possiblePaths.push( '/Applications/DBeaver.app/Contents/MacOS/dbeaver', path.join(os.homedir(), 'Applications', 'DBeaver.app', 'Contents', 'MacOS', 'dbeaver'), '/usr/local/bin/dbeaver', 'dbeaver' // fallback to PATH ); } else { // Linux and other Unix-like systems possiblePaths.push( '/usr/bin/dbeaver', '/usr/local/bin/dbeaver', '/opt/dbeaver/dbeaver', '/snap/bin/dbeaver', path.join(os.homedir(), '.local', 'bin', 'dbeaver'), path.join(os.homedir(), 'bin', 'dbeaver'), 'dbeaver' // fallback to PATH ); } // Find first existing executable for (const dbPath of possiblePaths) { if (fs.existsSync(dbPath)) { try { fs.accessSync(dbPath, fs.constants.X_OK); return dbPath; } catch (error) { // Not executable, continue searching continue; } } } // Return fallback (will rely on system PATH) const fallback = platform === 'win32' ? 'dbeaver.exe' : 'dbeaver'; console.warn(`DBeaver executable not found in standard locations. Using fallback: ${fallback}`); return fallback; } /** * Validate SQL query for basic safety */ export function validateQuery(query: string): string | null { if (!query || query.trim().length === 0) { return 'Query cannot be empty'; } const trimmedQuery = query.trim().toLowerCase(); // Block potentially dangerous operations const dangerousPatterns = [ /drop\s+database/i, /drop\s+schema/i, /truncate\s+table/i, /delete\s+from\s+\w+\s*$/i, // DELETE without WHERE clause /update\s+\w+\s+set\s+.*\s*$/i, // UPDATE without WHERE clause /grant\s+/i, /revoke\s+/i, /create\s+user/i, /drop\s+user/i, /alter\s+user/i, /shutdown/i, /restart/i ]; for (const pattern of dangerousPatterns) { if (pattern.test(trimmedQuery)) { return `Potentially dangerous query detected. Query blocked for safety.`; } } // Warn about operations that modify data const modifyingPatterns = [ /^insert\s+/i, /^update\s+/i, /^delete\s+/i, /^create\s+/i, /^alter\s+/i, /^drop\s+/i ]; for (const pattern of modifyingPatterns) { if (pattern.test(trimmedQuery)) { // Allow but note - could add confirmation in future break; } } return null; // Query is valid } /** * Sanitize connection ID to prevent injection */ export function sanitizeConnectionId(connectionId: string): string { if (!connectionId || typeof connectionId !== 'string') { throw new Error('Connection ID must be a non-empty string'); } // Remove potentially dangerous characters const sanitized = connectionId.replace(/[^a-zA-Z0-9_\-\.]/g, ''); if (sanitized.length === 0) { throw new Error('Connection ID contains no valid characters'); } return sanitized; } /** * Format error messages consistently */ export function formatError(error: unknown): string { if (error instanceof Error) { return error.message; } if (typeof error === 'string') { return error; } return String(error); } /** * Get test query based on database driver */ export function getTestQuery(driver: string): string { const driverLower = driver.toLowerCase(); if (driverLower.includes('postgresql') || driverLower.includes('postgres')) { return 'SELECT version();'; } else if (driverLower.includes('mysql')) { return 'SELECT version();'; } else if (driverLower.includes('oracle')) { return 'SELECT * FROM dual;'; } else if (driverLower.includes('sqlite')) { return 'SELECT sqlite_version();'; } else if (driverLower.includes('mssql') || driverLower.includes('sqlserver')) { return 'SELECT @@VERSION;'; } else if (driverLower.includes('mongodb')) { return 'db.version()'; } else if (driverLower.includes('redis')) { return 'INFO server'; } else { // Generic test query return 'SELECT 1;'; } } /** * Build schema query based on database driver */ export function buildSchemaQuery(driver: string, tableName: string): string { const driverLower = driver.toLowerCase(); if (driverLower.includes('postgresql') || driverLower.includes('postgres')) { return ` SELECT column_name, data_type, is_nullable, column_default, character_maximum_length, numeric_precision, numeric_scale FROM information_schema.columns WHERE table_name = '${tableName}' ORDER BY ordinal_position; `; } else if (driverLower.includes('mysql')) { return ` SELECT COLUMN_NAME as column_name, DATA_TYPE as data_type, IS_NULLABLE as is_nullable, COLUMN_DEFAULT as column_default, CHARACTER_MAXIMUM_LENGTH as character_maximum_length, NUMERIC_PRECISION as numeric_precision, NUMERIC_SCALE as numeric_scale, COLUMN_KEY as column_key, EXTRA as extra FROM information_schema.COLUMNS WHERE TABLE_NAME = '${tableName}' ORDER BY ORDINAL_POSITION; `; } else if (driverLower.includes('sqlite')) { return `PRAGMA table_info(${tableName});`; } else if (driverLower.includes('oracle')) { return ` SELECT column_name, data_type, nullable, data_default, data_length, data_precision, data_scale FROM user_tab_columns WHERE table_name = UPPER('${tableName}') ORDER BY column_id; `; } else if (driverLower.includes('mssql') || driverLower.includes('sqlserver')) { return ` SELECT COLUMN_NAME as column_name, DATA_TYPE as data_type, IS_NULLABLE as is_nullable, COLUMN_DEFAULT as column_default, CHARACTER_MAXIMUM_LENGTH as character_maximum_length, NUMERIC_PRECISION as numeric_precision, NUMERIC_SCALE as numeric_scale FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '${tableName}' ORDER BY ORDINAL_POSITION; `; } else { // Generic fallback return ` SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name = '${tableName}'; `; } } /** * Build list tables query based on database driver */ export function buildListTablesQuery(driver: string, schema?: string, includeViews: boolean = false): string { const driverLower = driver.toLowerCase(); if (driverLower.includes('postgresql') || driverLower.includes('postgres')) { let query = ` SELECT table_name, table_type, table_schema FROM information_schema.tables WHERE table_schema NOT IN ('information_schema', 'pg_catalog') `; if (schema) { query += ` AND table_schema = '${schema}'`; } if (!includeViews) { query += ` AND table_type = 'BASE TABLE'`; } query += ` ORDER BY table_schema, table_name;`; return query; } else if (driverLower.includes('mysql')) { let query = ` SELECT TABLE_NAME as table_name, TABLE_TYPE as table_type, TABLE_SCHEMA as table_schema FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys') `; if (schema) { query += ` AND TABLE_SCHEMA = '${schema}'`; } if (!includeViews) { query += ` AND TABLE_TYPE = 'BASE TABLE'`; } query += ` ORDER BY TABLE_SCHEMA, TABLE_NAME;`; return query; } else if (driverLower.includes('sqlite')) { let query = ` SELECT name as table_name, type as table_type FROM sqlite_master WHERE type IN ('table'${includeViews ? ", 'view'" : ''}) AND name NOT LIKE 'sqlite_%' ORDER BY name; `; return query; } else if (driverLower.includes('oracle')) { let query = ` SELECT table_name, 'TABLE' as table_type, owner as table_schema FROM all_tables `; if (schema) { query += ` WHERE owner = UPPER('${schema}')`; } if (includeViews) { query += ` UNION ALL SELECT view_name as table_name, 'VIEW' as table_type, owner as table_schema FROM all_views `; if (schema) { query += ` WHERE owner = UPPER('${schema}')`; } } query += ` ORDER BY table_name;`; return query; } else { // Generic fallback let query = ` SELECT table_name, table_type, table_schema FROM information_schema.tables `; if (schema) { query += ` WHERE table_schema = '${schema}'`; } if (!includeViews) { query += `${schema ? ' AND' : ' WHERE'} table_type = 'BASE TABLE'`; } query += ` ORDER BY table_schema, table_name;`; return query; } } /** * Parse database version from query result */ export function parseVersionFromResult(result: any): string | undefined { if (!result || !result.rows || result.rows.length === 0) { return undefined; } const firstRow = result.rows[0]; if (Array.isArray(firstRow) && firstRow.length > 0) { return String(firstRow[0]); } else if (firstRow && typeof firstRow === 'object') { const firstValue = Object.values(firstRow)[0]; return firstValue !== undefined ? String(firstValue) : undefined; } return undefined; } /** * Convert query results to CSV format */ export function convertToCSV(columns: string[], rows: any[][]): string { if (rows.length === 0) return ''; // Create CSV header row let csv = columns.map(col => `"${col.replace(/"/g, '""')}"`).join(',') + '\n'; // Add data rows rows.forEach(row => { const values = row.map(val => { // Handle null/undefined values if (val === null || val === undefined) { return ''; } // Convert to string and escape quotes const strVal = String(val); if (strVal.includes(',') || strVal.includes('"') || strVal.includes('\n')) { return `"${strVal.replace(/"/g, '""')}"`; } return strVal; }); csv += values.join(',') + '\n'; }); return csv; }

Latest Blog Posts

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/srthkdev/dbeaver-mcp-server'

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