Skip to main content
Glama

MySQL MCP Server

by yuki777
connection.ts6.28 kB
import mysql, { Pool, PoolConnection, PoolOptions, SslOptions, RowDataPacket, OkPacket, ResultSetHeader } from 'mysql2/promise'; import { MySQLConfig, QueryResult } from '../core/types.js'; /** * MySQLデータベース接続を管理するクラス */ export class MySQLConnection { private pool: Pool | null = null; private config: MySQLConfig; private isConnected: boolean = false; private queryTimeout: number; /** * コンストラクタ * @param config MySQL接続設定 * @param queryTimeout クエリタイムアウト(ミリ秒) */ constructor(config: MySQLConfig, queryTimeout: number = 30000) { this.config = config; this.queryTimeout = queryTimeout; } /** * 接続設定を更新する * @param config 新しい接続設定 */ public updateConfig(config: Partial<MySQLConfig>): void { this.config = { ...this.config, ...config }; } /** * クエリタイムアウト設定を更新する * @param timeout 新しいタイムアウト(ミリ秒) */ public updateQueryTimeout(timeout: number): void { this.queryTimeout = timeout; } /** * 現在の接続設定を取得する * @returns 現在の接続設定 */ public getConfig(): MySQLConfig { return { ...this.config }; } /** * MySQL接続プールを初期化 * @param forceConnect 強制的に接続を試みるかどうか */ public async initialize(forceConnect: boolean = true): Promise<void> { try { if (this.pool) { return; } // 接続情報が十分でない場合は初期化のみ行い、接続は行わない const requiredFields = ['host', 'port', 'user']; const hasRequiredFields = requiredFields.every(field => this.config[field as keyof MySQLConfig] !== undefined && this.config[field as keyof MySQLConfig] !== null && this.config[field as keyof MySQLConfig] !== '' ); if (!forceConnect || !hasRequiredFields) { console.log('MySQL connection initialized but not connected'); return; } const poolOptions: PoolOptions = { host: this.config.host, port: this.config.port, user: this.config.user, password: this.config.password, database: this.config.database, ssl: this.config.ssl as string | SslOptions | undefined, connectionLimit: this.config.connectionLimit || 10, timezone: this.config.timezone || 'local', charset: this.config.charset || 'utf8mb4', }; this.pool = mysql.createPool(poolOptions); // 接続テスト await this.ping(); this.isConnected = true; console.log(`MySQL connection established to ${this.config.host}:${this.config.port}`); } catch (error) { this.isConnected = false; this.pool = null; console.error('Failed to initialize MySQL connection pool:', error); throw new Error(`MySQL connection failed: ${(error as Error).message}`); } } /** * 現在の設定でデータベースに接続する * 既に接続が確立されている場合は一度閉じて再接続する */ public async connect(): Promise<void> { // 既存の接続を閉じる await this.close(); // 新しい接続を確立 await this.initialize(true); } /** * 接続状態を確認 * @returns 接続状態 */ public isConnectedToDatabase(): boolean { return this.isConnected; } /** * 接続情報の詳細を取得 * @returns 接続情報の詳細 */ public getConnectionInfo(): Record<string, any> { return { isConnected: this.isConnected, host: this.config.host, port: this.config.port, user: this.config.user, database: this.config.database, // パスワードはセキュリティ上の理由で含めない }; } /** * 接続を確認(ping) */ public async ping(): Promise<boolean> { if (!this.pool) { throw new Error('Connection pool not initialized'); } const conn = await this.pool.getConnection(); try { await conn.ping(); return true; } finally { conn.release(); } } /** * SQLクエリを実行 * @param sql SQLクエリ文 * @param params クエリパラメータ * @returns クエリ結果 */ public async executeQuery(sql: string, params: any[] = []): Promise<QueryResult> { if (!this.isConnected || !this.pool) { throw new Error('Database not connected. Please connect to a database first.'); } const conn = await this.pool.getConnection(); try { // クエリタイムアウトの設定 await conn.query(`SET SESSION MAX_EXECUTION_TIME=${Math.floor(this.queryTimeout / 1000) * 1000}`); const [rows, fields] = await conn.query(sql, params); // クエリ結果の整形 if (Array.isArray(rows)) { return { data: rows as any[], fields: fields as any[] }; } else { // INSERT, UPDATE, DELETE 等の結果 const okPacket = rows as OkPacket | ResultSetHeader; return { data: [], metadata: { affectedRows: okPacket.affectedRows, insertId: okPacket.insertId, changedRows: 'changedRows' in okPacket ? okPacket.changedRows : undefined } }; } } catch (error) { console.error('Query execution failed:', error); throw new Error(`Query failed: ${(error as Error).message}`); } finally { conn.release(); } } /** * トランザクションを取得 * @returns トランザクション用の接続 */ public async getTransaction(): Promise<PoolConnection> { if (!this.pool) { await this.initialize(); } if (!this.pool) { throw new Error('Connection pool not initialized'); } const conn = await this.pool.getConnection(); await conn.beginTransaction(); return conn; } /** * 接続を閉じる */ public async close(): Promise<void> { if (this.pool) { await this.pool.end(); this.pool = null; this.isConnected = false; console.log('MySQL connection pool closed'); } } }

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/yuki777/mysql-mcp-server'

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