Skip to main content
Glama
cafe24-wjsong

Ectlocal Connect MCP Server

database.ts3.91 kB
import { Pool, PoolConfig } from 'pg'; import * as dotenv from 'dotenv'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; // ESM에서 __dirname 대체 const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // 프로젝트 루트의 .env 파일 로드 dotenv.config({ path: join(__dirname, '..', '.env') }); export interface DatabaseConfig { host: string; port: number; database: string; user: string; password: string; schema: string; } export class DatabaseManager { private pool: Pool; private config: DatabaseConfig; constructor() { this.config = { host: process.env.DB_HOST || 'ectlocal.cafe24.com', port: parseInt(process.env.DB_PORT || '5434'), database: process.env.DB_NAME || 'mall', user: process.env.DB_USER || 'malluser', password: process.env.ECTLOCAL_DB_PASSWORD || '', schema: process.env.DB_SCHEMA || 'ec_ectlocal' }; if (!this.config.password) { throw new Error('ECTLOCAL_DB_PASSWORD 환경변수가 설정되지 않았습니다.'); } const poolConfig: PoolConfig = { host: this.config.host, port: this.config.port, database: this.config.database, user: this.config.user, password: this.config.password, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, }; this.pool = new Pool(poolConfig); } async query(text: string, params?: any[]): Promise<any> { const client = await this.pool.connect(); try { await client.query(`SET search_path TO ${this.config.schema}`); const result = await client.query(text, params); return result; } finally { client.release(); } } async getTableStructure(tableName: string) { const queries = { primaryKeys: ` SELECT kcu.column_name FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name WHERE tc.table_schema = $1 AND tc.table_name = $2 AND tc.constraint_type = 'PRIMARY KEY' ORDER BY kcu.ordinal_position; `, indexes: ` SELECT indexname, indexdef FROM pg_indexes WHERE schemaname = $1 AND tablename = $2; `, columns: ` SELECT ordinal_position AS pos, column_name, data_type, CASE WHEN character_maximum_length IS NOT NULL THEN '(' || character_maximum_length || ')' ELSE '' END AS length, is_nullable AS nullable, column_default AS default_value FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 ORDER BY ordinal_position; `, stats: ` SELECT n_live_tup AS row_count, pg_size_pretty(pg_total_relation_size($1 || '.' || $2)) AS total_size FROM pg_stat_user_tables WHERE schemaname = $1 AND relname = $2; ` }; const [primaryKeys, indexes, columns, stats] = await Promise.all([ this.query(queries.primaryKeys, [this.config.schema, tableName]), this.query(queries.indexes, [this.config.schema, tableName]), this.query(queries.columns, [this.config.schema, tableName]), this.query(queries.stats, [this.config.schema, tableName]) ]); return { primaryKeys: primaryKeys.rows, indexes: indexes.rows, columns: columns.rows, stats: stats.rows[0] || {} }; } async getAllTables() { const result = await this.query( 'SELECT tablename FROM pg_tables WHERE schemaname = $1 ORDER BY tablename', [this.config.schema] ); return result.rows; } async close() { await this.pool.end(); } }

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/cafe24-wjsong/mcp-ectlocal-connect'

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