Skip to main content
Glama
intecrel

Industrial MCP Server

by intecrel
route.ts8.02 kB
import { NextRequest, NextResponse } from 'next/server' /** * Audit Tables Migration API Endpoint * * This endpoint can be called during deployment to ensure audit tables are created. * Protected by API key authentication. */ export async function POST(request: NextRequest) { try { // Import the migration function dynamically to avoid build-time bundling issues // eslint-disable-next-line @typescript-eslint/no-require-imports const { runMigration } = require('../../../../scripts/migrate-audit-tables.js') // Verify API key const apiKey = request.headers.get('x-api-key') const expectedApiKey = process.env.API_KEY if (!apiKey || !expectedApiKey || apiKey !== expectedApiKey) { return NextResponse.json( { error: 'Unauthorized: Invalid or missing API key' }, { status: 401 } ) } console.log('🚀 Starting audit migration via API endpoint...') // Run the migration await runMigration() return NextResponse.json({ success: true, message: 'Audit tables migration completed successfully', timestamp: new Date().toISOString() }) } catch (error: any) { console.error('❌ Migration API endpoint error:', error) return NextResponse.json( { success: false, error: 'Migration failed', message: error.message, timestamp: new Date().toISOString() }, { status: 500 } ) } } export async function GET(request: NextRequest) { try { // Verify API key const apiKey = request.headers.get('x-api-key') const expectedApiKey = process.env.API_KEY if (!apiKey || !expectedApiKey || apiKey !== expectedApiKey) { return NextResponse.json( { error: 'Unauthorized: Invalid or missing API key' }, { status: 401 } ) } // Check migration status (table existence) // eslint-disable-next-line @typescript-eslint/no-require-imports const mysql = require('mysql2/promise') // Environment-aware database selection const isLocal = process.env.NODE_ENV !== 'production' && !process.env.VERCEL_ENV const isProduction = process.env.VERCEL_ENV === 'production' || process.env.NODE_ENV === 'production' let config: any // Priority 1: Local MySQL if (isLocal && process.env.MYSQL_HOST) { config = { host: process.env.MYSQL_HOST, port: parseInt(process.env.MYSQL_PORT || '3306'), user: process.env.MYSQL_USERNAME || 'root', password: process.env.MYSQL_PASSWORD, database: process.env.MYSQL_DATABASE, connectTimeout: 30000 } } // Priority 2: Cloud SQL Connector (Vercel/Serverless) else if (process.env.CLOUD_SQL_INSTANCE_CONNECTION_NAME) { const database = isProduction ? (process.env.CLOUD_SQL_DB_PRIMARY || process.env.CLOUD_SQL_DB_STAGING) : (process.env.CLOUD_SQL_DB_STAGING || process.env.CLOUD_SQL_DB_PRIMARY) config = { instanceConnectionName: process.env.CLOUD_SQL_INSTANCE_CONNECTION_NAME, user: process.env.CLOUD_SQL_USERNAME || 'mcp_user', password: process.env.CLOUD_SQL_PASSWORD, database: database, useConnector: true } } // Priority 3: Cloud SQL Direct (with host) else if (process.env.CLOUD_SQL_HOST) { const database = isProduction ? (process.env.CLOUD_SQL_DB_PRIMARY || process.env.CLOUD_SQL_DB_STAGING) : (process.env.CLOUD_SQL_DB_STAGING || process.env.CLOUD_SQL_DB_PRIMARY) config = { host: process.env.CLOUD_SQL_HOST, port: parseInt(process.env.CLOUD_SQL_PORT || '3306'), user: process.env.CLOUD_SQL_USERNAME || 'mcp_user', password: process.env.CLOUD_SQL_PASSWORD, database: database, connectTimeout: 30000 } } if (!config.password || !config.database) { return NextResponse.json( { success: false, error: 'Configuration error', message: 'Missing required database configuration. Local: MYSQL_HOST/PASSWORD/DATABASE, Cloud: CLOUD_SQL_INSTANCE_CONNECTION_NAME or CLOUD_SQL_HOST, plus CLOUD_SQL_PASSWORD and CLOUD_SQL_DB_PRIMARY or CLOUD_SQL_DB_STAGING', timestamp: new Date().toISOString() }, { status: 500 } ) } let connection // Use Cloud SQL Connector for serverless environments if (config.useConnector) { // eslint-disable-next-line @typescript-eslint/no-require-imports const { Connector } = require('@google-cloud/cloud-sql-connector') // eslint-disable-next-line @typescript-eslint/no-require-imports const { writeFileSync, unlinkSync } = require('fs') // eslint-disable-next-line @typescript-eslint/no-require-imports const { tmpdir } = require('os') // eslint-disable-next-line @typescript-eslint/no-require-imports const path = require('path') let tempCredentialsFile: string | null = null const originalGoogleCredentials = process.env.GOOGLE_APPLICATION_CREDENTIALS // Check if GOOGLE_APPLICATION_CREDENTIALS is inline JSON or file path const googleCreds = process.env.GOOGLE_APPLICATION_CREDENTIALS if (googleCreds && googleCreds.trim().startsWith('{')) { // Inline JSON credentials - write to temp file try { const credentials = JSON.parse(googleCreds) // Write to temporary file const tempPath = path.join(tmpdir(), `gcp-credentials-${Date.now()}.json`) writeFileSync(tempPath, googleCreds) tempCredentialsFile = tempPath process.env.GOOGLE_APPLICATION_CREDENTIALS = tempPath } catch (error: any) { console.warn(`Failed to parse inline credentials: ${error.message}`) } } try { const connector = new Connector() const clientOpts = await connector.getOptions({ instanceConnectionName: config.instanceConnectionName }) connection = await mysql.createConnection({ ...clientOpts, user: config.user, password: config.password, database: config.database }) } finally { // Restore original credentials environment variable if (originalGoogleCredentials) { process.env.GOOGLE_APPLICATION_CREDENTIALS = originalGoogleCredentials } else { delete process.env.GOOGLE_APPLICATION_CREDENTIALS } // Clean up temp file if created if (tempCredentialsFile) { try { unlinkSync(tempCredentialsFile) } catch (error) { // Ignore cleanup errors } } } } else { // Direct connection connection = await mysql.createConnection(config) } try { const [rows] = await connection.execute(` SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND table_name LIKE '%audit%' ORDER BY table_name `, [config.database]) const existingTables = rows.map((row: any) => row.table_name || row.TABLE_NAME) const expectedTables = ['audit_events', 'database_audit_events', 'audit_retention_policy'] const missingTables = expectedTables.filter(table => !existingTables.includes(table)) await connection.end() return NextResponse.json({ success: true, migration_status: { existing_tables: existingTables, expected_tables: expectedTables, missing_tables: missingTables, is_complete: missingTables.length === 0 }, timestamp: new Date().toISOString() }) } finally { await connection.end() } } catch (error: any) { console.error('❌ Migration status check error:', error) return NextResponse.json( { success: false, error: 'Failed to check migration status', message: error.message, timestamp: new Date().toISOString() }, { status: 500 } ) } }

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/intecrel/industrial-mcp'

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