@imrieul/mysql-mcp-server 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @imrieul/mysql-mcp-server
2
2
 
3
- [한국어](https://github.com/ImRieul/mysql-mcp-server/blob/main/README.ko.md) | [日本語](https://github.com/ImRieul/mysql-mcp-server/blob/main/README.ja.md) | [中文](https://github.com/ImRieul/mysql-mcp-server/blob/main/README.zh.md) | [Español](https://github.com/ImRieul/mysql-mcp-server/blob/main/README.es.md) | [Português](https://github.com/ImRieul/mysql-mcp-server/blob/main/README.pt.md) | [Français](https://github.com/ImRieul/mysql-mcp-server/blob/main/README.fr.md) | [Русский](https://github.com/ImRieul/mysql-mcp-server/blob/main/README.ru.md)
3
+ [한국어](https://github.com/ImRieul/mysql-mcp-server/blob/main/docs/translations/README.ko.md) | [日本語](https://github.com/ImRieul/mysql-mcp-server/blob/main/docs/translations/README.ja.md) | [中文](https://github.com/ImRieul/mysql-mcp-server/blob/main/docs/translations/README.zh.md) | [Español](https://github.com/ImRieul/mysql-mcp-server/blob/main/docs/translations/README.es.md) | [Português](https://github.com/ImRieul/mysql-mcp-server/blob/main/docs/translations/README.pt.md) | [Français](https://github.com/ImRieul/mysql-mcp-server/blob/main/docs/translations/README.fr.md) | [Русский](https://github.com/ImRieul/mysql-mcp-server/blob/main/docs/translations/README.ru.md)
4
4
 
5
5
  A simple MySQL [MCP](https://modelcontextprotocol.io/) server.
6
6
 
package/dist/index.js CHANGED
@@ -159,6 +159,7 @@ function createQueryRunner(pool, options) {
159
159
  }
160
160
 
161
161
  // src/server.ts
162
+ import { createRequire } from "module";
162
163
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
163
164
 
164
165
  // src/tools/query.ts
@@ -829,14 +830,14 @@ function registerAllTools(server, runner, readonly, maxRows) {
829
830
  function createMcpServer(runner, readonly, maxRows) {
830
831
  const server = new McpServer({
831
832
  name: "@imrieul/mysql-mcp-server",
832
- version: "0.1.0"
833
+ version: createRequire(import.meta.url)("../package.json").version
833
834
  });
834
835
  registerAllTools(server, runner, readonly, maxRows);
835
836
  return server;
836
837
  }
837
838
 
838
839
  // src/index.ts
839
- import { createRequire } from "module";
840
+ import { createRequire as createRequire2 } from "module";
840
841
  var HELP_TEXT = `Usage: mysql-mcp-server [options] [mysql://user:pass@host:port/db]
841
842
 
842
843
  MySQL MCP Server - Model Context Protocol server for MySQL database operations
@@ -868,7 +869,7 @@ async function main() {
868
869
  process.exit(0);
869
870
  }
870
871
  if (args.version) {
871
- const require2 = createRequire(import.meta.url);
872
+ const require2 = createRequire2(import.meta.url);
872
873
  const pkg = require2("../package.json");
873
874
  console.log(pkg.version);
874
875
  process.exit(0);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/connection.ts","../src/query-runner.ts","../src/server.ts","../src/tools/query.ts","../src/tools/error-hint.ts","../src/tools/validate-input.ts","../src/tools/execute.ts","../src/tools/list-databases.ts","../src/tools/list-tables.ts","../src/tools/resolve-database.ts","../src/tools/sql-escape.ts","../src/tools/describe-table.ts","../src/tools/format-column.ts","../src/tools/describe-all-tables.ts","../src/tools/add-comment.ts","../src/tools/index.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { parseArgs, resolveConfig } from './config.js';\nimport { createConnectionManager } from './connection.js';\nimport { createQueryRunner } from './query-runner.js';\nimport { createMcpServer } from './server.js';\nimport { createRequire } from 'module';\n\nconst HELP_TEXT = `Usage: mysql-mcp-server [options] [mysql://user:pass@host:port/db]\n\nMySQL MCP Server - Model Context Protocol server for MySQL database operations\n\nOptions:\n --readonly Enable read-only mode (blocks execute and add_comment)\n --help, -h Show this help message\n --version Show version number\n\nEnvironment variables:\n MYSQL_HOST MySQL host (required if no connection string)\n MYSQL_PORT MySQL port (default: 3306)\n MYSQL_USER MySQL user (required if no connection string)\n MYSQL_PASSWORD MySQL password (required if no connection string)\n MYSQL_DATABASE Default database\n MYSQL_READONLY Read-only mode (true/false)\n MYSQL_MAX_ROWS Max rows for SELECT queries (default: 100)\n MYSQL_QUERY_TIMEOUT Query timeout in ms (default: 30000, 0 to disable)\n MYSQL_SSL Enable SSL (true/false)\n\nExamples:\n mysql-mcp-server mysql://root:pass@localhost:3306/mydb\n mysql-mcp-server --readonly\n MYSQL_HOST=localhost MYSQL_USER=root MYSQL_PASSWORD=pass mysql-mcp-server`;\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2));\n\n if (args.help) {\n console.log(HELP_TEXT);\n process.exit(0);\n }\n\n if (args.version) {\n const require = createRequire(import.meta.url);\n const pkg = require('../package.json') as { version: string };\n console.log(pkg.version);\n process.exit(0);\n }\n\n const config = resolveConfig(process.argv.slice(2));\n const connectionManager = createConnectionManager(config.mysql, { ssl: config.ssl });\n const runner = createQueryRunner(connectionManager.getPool(), {\n readonly: config.readonly,\n queryTimeout: config.queryTimeout,\n });\n\n const server = createMcpServer(runner, config.readonly, config.maxRows);\n const transport = new StdioServerTransport();\n\n const shutdown = async () => {\n await server.close();\n await connectionManager.close();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n process.stdin.on('end', shutdown);\n\n console.error('MySQL MCP Server starting...');\n console.error(`Readonly mode: ${config.readonly}`);\n console.error(`Query timeout: ${config.queryTimeout}ms`);\n console.error(`SSL: ${config.ssl}`);\n\n await server.connect(transport);\n console.error('MySQL MCP Server connected via stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n","export interface MySQLConfig {\n host: string;\n port: number;\n user: string;\n password: string;\n database?: string;\n}\n\nexport interface AppConfig {\n mysql: MySQLConfig;\n readonly: boolean;\n maxRows: number;\n queryTimeout: number;\n ssl: boolean;\n}\n\nexport function parseConnectionString(connStr: string): MySQLConfig {\n let url: URL;\n try {\n url = new URL(connStr);\n } catch {\n throw new Error(`Invalid connection string: ${connStr}`);\n }\n\n if (url.protocol !== 'mysql:') {\n throw new Error(`Expected mysql:// protocol, got ${url.protocol}`);\n }\n\n const database = url.pathname.slice(1) || undefined;\n\n return {\n host: url.hostname,\n port: url.port ? parseInt(url.port, 10) : 3306,\n user: decodeURIComponent(url.username),\n password: decodeURIComponent(url.password),\n database,\n };\n}\n\nexport function parseEnvConfig(env: Record<string, string | undefined>): MySQLConfig {\n const host = env.MYSQL_HOST;\n const user = env.MYSQL_USER;\n const password = env.MYSQL_PASSWORD;\n\n if (!host) throw new Error('Missing required environment variable: MYSQL_HOST');\n if (!user) throw new Error('Missing required environment variable: MYSQL_USER');\n if (!password) throw new Error('Missing required environment variable: MYSQL_PASSWORD');\n\n return {\n host,\n port: env.MYSQL_PORT ? parseInt(env.MYSQL_PORT, 10) : 3306,\n user,\n password,\n database: env.MYSQL_DATABASE || undefined,\n };\n}\n\nexport interface ParsedArgs {\n connectionString?: string;\n readonly: boolean;\n help: boolean;\n version: boolean;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n let connectionString: string | undefined;\n let readonly = false;\n let help = false;\n let version = false;\n\n for (const arg of argv) {\n if (arg === '--readonly') {\n readonly = true;\n } else if (arg === '--help' || arg === '-h') {\n help = true;\n } else if (arg === '--version') {\n version = true;\n } else if (arg.startsWith('mysql://')) {\n connectionString = arg;\n }\n }\n\n return { connectionString, readonly, help, version };\n}\n\nexport function resolveConfig(argv: string[], env: Record<string, string | undefined> = process.env): AppConfig {\n const args = parseArgs(argv);\n\n const mysql = args.connectionString ? parseConnectionString(args.connectionString) : parseEnvConfig(env);\n\n const readonly = args.readonly || env.MYSQL_READONLY === 'true';\n const maxRows = env.MYSQL_MAX_ROWS ? parseInt(env.MYSQL_MAX_ROWS, 10) : 100;\n const queryTimeout = env.MYSQL_QUERY_TIMEOUT !== undefined ? parseInt(env.MYSQL_QUERY_TIMEOUT, 10) : 30000;\n const ssl = env.MYSQL_SSL === 'true';\n\n return { mysql, readonly, maxRows, queryTimeout, ssl };\n}\n","import mysql from 'mysql2/promise';\nimport type { Pool } from 'mysql2/promise';\nimport type { MySQLConfig } from './config.js';\n\nexport interface ConnectionManager {\n getPool(): Pool;\n close(): Promise<void>;\n}\n\nexport interface ConnectionOptions {\n ssl?: boolean;\n}\n\nexport function createConnectionManager(config: MySQLConfig, options?: ConnectionOptions): ConnectionManager {\n const poolOptions: mysql.PoolOptions = {\n host: config.host,\n port: config.port,\n user: config.user,\n password: config.password,\n database: config.database,\n connectionLimit: 5,\n waitForConnections: true,\n };\n\n if (options?.ssl) {\n poolOptions.ssl = { rejectUnauthorized: true };\n }\n\n const pool = mysql.createPool(poolOptions);\n\n return {\n getPool() {\n return pool;\n },\n async close() {\n await pool.end();\n },\n };\n}\n","import type { Pool } from 'mysql2/promise';\n\ntype QueryFn = (sql: string) => Promise<[unknown, unknown]>;\n\nexport interface QueryRunner {\n query(sql: string): Promise<[unknown, unknown]>;\n withConnection<T>(fn: (query: QueryFn) => Promise<T>): Promise<T>;\n}\n\nexport class QueryTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Query timeout after ${timeoutMs}ms`);\n this.name = 'QueryTimeoutError';\n }\n}\n\nexport interface QueryRunnerOptions {\n readonly: boolean;\n queryTimeout: number;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {\n if (timeoutMs <= 0) return promise;\n\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => setTimeout(() => reject(new QueryTimeoutError(timeoutMs)), timeoutMs)),\n ]);\n}\n\nexport function createQueryRunner(pool: Pool, options: QueryRunnerOptions): QueryRunner {\n const { readonly, queryTimeout } = options;\n\n return {\n async query(sql: string): Promise<[unknown, unknown]> {\n if (!readonly) {\n return withTimeout(pool.query(sql) as Promise<[unknown, unknown]>, queryTimeout);\n }\n\n const conn = await pool.getConnection();\n try {\n await conn.query('SET SESSION TRANSACTION READ ONLY');\n await conn.beginTransaction();\n const result = await withTimeout(conn.query(sql) as Promise<[unknown, unknown]>, queryTimeout);\n await conn.rollback();\n return result;\n } catch (error) {\n try {\n await conn.rollback();\n } catch {\n // rollback 실패 무시\n }\n throw error;\n } finally {\n conn.release();\n }\n },\n\n async withConnection<T>(fn: (query: QueryFn) => Promise<T>): Promise<T> {\n const conn = await pool.getConnection();\n try {\n if (readonly) {\n await conn.query('SET SESSION TRANSACTION READ ONLY');\n await conn.beginTransaction();\n }\n\n const queryFn: QueryFn = (sql: string) =>\n withTimeout(conn.query(sql) as Promise<[unknown, unknown]>, queryTimeout);\n\n const result = await fn(queryFn);\n\n if (readonly) {\n await conn.rollback();\n }\n\n return result;\n } catch (error) {\n if (readonly) {\n try {\n await conn.rollback();\n } catch {\n // rollback 실패 무시\n }\n }\n throw error;\n } finally {\n conn.release();\n }\n },\n };\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { QueryRunner } from './query-runner.js';\nimport { registerAllTools } from './tools/index.js';\n\nexport function createMcpServer(runner: QueryRunner, readonly: boolean, maxRows: number): McpServer {\n const server = new McpServer({\n name: '@imrieul/mysql-mcp-server',\n version: '0.1.0',\n });\n\n registerAllTools(server, runner, readonly, maxRows);\n\n return server;\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { validateSql } from './validate-input.js';\n\nexport const queryToolName = 'query';\n\nexport const queryToolConfig = {\n title: 'Query',\n description:\n 'Execute a read-only SQL query (SELECT, SHOW, DESCRIBE, EXPLAIN). ' +\n 'LIMIT is auto-appended to SELECT/WITH queries without one (default: server maxRows). ' +\n 'Prefer specific columns over SELECT * to reduce response size. ' +\n 'For data modification, use the \"execute\" tool instead.',\n inputSchema: {\n sql: z\n .string()\n .describe(\n 'The SQL query to execute. Only SELECT, SHOW, DESCRIBE, EXPLAIN, and WITH (CTE) statements are allowed.',\n ),\n },\n};\n\nconst ALLOWED_PREFIXES = ['SELECT', 'SHOW', 'DESCRIBE', 'EXPLAIN', 'WITH'];\nconst LIMIT_PREFIXES = ['SELECT', 'WITH'];\n\nfunction needsLimit(normalized: string): boolean {\n if (!LIMIT_PREFIXES.some((p) => normalized.startsWith(p))) return false;\n return !/\\bLIMIT\\b/i.test(normalized);\n}\n\nexport function createQueryHandler(runner: QueryRunner, maxRows: number) {\n return async ({ sql }: { sql: string }) => {\n const validation = validateSql(sql);\n if (!validation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: validation.message! }],\n };\n }\n\n const normalized = sql.trim().toUpperCase();\n const isAllowed = ALLOWED_PREFIXES.some((prefix) => normalized.startsWith(prefix));\n\n if (!isAllowed) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Only SELECT, SHOW, DESCRIBE, EXPLAIN queries are allowed. Use the \"execute\" tool for data modification.',\n },\n ],\n };\n }\n\n try {\n const finalSql = needsLimit(normalized) ? `${sql.trim()} LIMIT ${maxRows}` : sql;\n const [rows] = await runner.query(finalSql);\n const arr = rows as Record<string, unknown>[];\n if (arr.length === 0) {\n return { content: [{ type: 'text' as const, text: '(empty)' }] };\n }\n const cols = Object.keys(arr[0]);\n const data = arr.map((r) => cols.map((c) => r[c]));\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ columns: cols, rows: data }) }],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","const HINTS: [RegExp, string][] = [\n [/Table '.*' doesn't exist/i, 'Hint: use list_tables to check available tables.'],\n [/Unknown column/i, 'Hint: use describe_table to check column names.'],\n [/Unknown database/i, 'Hint: use list_databases to check available databases.'],\n [/Access denied/i, 'Hint: check database user permissions.'],\n [/ECONNREFUSED|ETIMEDOUT|ENOTFOUND/i, 'Hint: check MYSQL_HOST and MYSQL_PORT settings.'],\n [/ER_PARSE_ERROR/i, 'Hint: check SQL syntax.'],\n [/Query timeout/i, 'Hint: increase MYSQL_QUERY_TIMEOUT or optimize the query.'],\n];\n\nexport function formatError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n const hint = HINTS.find(([pattern]) => pattern.test(message));\n return hint ? `Error: ${message}\\n${hint[1]}` : `Error: ${message}`;\n}\n","/**\n * 에이전트 환각 대비 입력 검증 모듈\n * - 제어문자 거부 (탭/개행/캐리지리턴 제외)\n * - 식별자(테이블/컬럼명) 위험 패턴 거부\n */\n\nfunction hasControlChars(str: string): boolean {\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n // 허용: \\t(9), \\n(10), \\r(13)\n if (code === 9 || code === 10 || code === 13) continue;\n // 제어문자: 0x00-0x1f, 0x7f\n if (code <= 0x1f || code === 0x7f) return true;\n }\n return false;\n}\n\nconst DANGEROUS_IDENTIFIER_PATTERNS = [\n /;/, // SQL statement separator\n /--/, // SQL line comment\n /\\/\\*/, // SQL block comment start\n /\\*\\//, // SQL block comment end\n /\\\\/, // backslash escape\n];\n\nexport interface ValidationResult {\n valid: boolean;\n message?: string;\n}\n\nexport function validateSql(sql: string): ValidationResult {\n if (hasControlChars(sql)) {\n return {\n valid: false,\n message: 'Error: SQL contains control characters. Remove non-printable characters (tab and newline are allowed).',\n };\n }\n return { valid: true };\n}\n\nexport function validateIdentifier(name: string, label: string): ValidationResult {\n if (!name || name.trim().length === 0) {\n return { valid: false, message: `Error: ${label} name cannot be empty.` };\n }\n\n if (hasControlChars(name)) {\n return {\n valid: false,\n message: `Error: ${label} name contains control characters.`,\n };\n }\n\n for (const pattern of DANGEROUS_IDENTIFIER_PATTERNS) {\n if (pattern.test(name)) {\n return {\n valid: false,\n message: `Error: ${label} name contains dangerous characters (${pattern.source}). Use only valid MySQL identifier characters.`,\n };\n }\n }\n\n if (name.length > 64) {\n return {\n valid: false,\n message: `Error: ${label} name exceeds MySQL's 64-character limit.`,\n };\n }\n\n return { valid: true };\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { validateSql } from './validate-input.js';\n\nexport const executeToolName = 'execute';\n\nexport const executeToolConfig = {\n title: 'Execute',\n description:\n 'Execute a data modification SQL statement (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, etc.). ' +\n 'Set dryRun=true to validate without executing — uses EXPLAIN for DML, or previews the SQL for DDL. ' +\n 'Always confirm destructive operations (DROP, TRUNCATE, DELETE without WHERE) with the user before executing. ' +\n 'Not available in read-only mode.',\n inputSchema: {\n sql: z\n .string()\n .describe('The SQL statement to execute. SELECT statements are not allowed here; use the \"query\" tool instead.'),\n dryRun: z\n .boolean()\n .optional()\n .describe('If true, validates the statement via EXPLAIN without executing it. Defaults to false.'),\n },\n};\n\nexport function createExecuteHandler(runner: QueryRunner, isReadonly: boolean) {\n return async ({ sql, dryRun }: { sql: string; dryRun?: boolean }) => {\n if (isReadonly) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Server is in read-only mode. Data modification is not allowed.',\n },\n ],\n };\n }\n\n const validation = validateSql(sql);\n if (!validation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: validation.message! }],\n };\n }\n\n const normalized = sql.trim().toUpperCase();\n if (normalized.startsWith('SELECT') || normalized.startsWith('WITH')) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Use the \"query\" tool for SELECT statements.',\n },\n ],\n };\n }\n\n if (dryRun) {\n const DDL_PREFIXES = ['CREATE', 'DROP', 'ALTER', 'TRUNCATE', 'RENAME'];\n const isDdl = DDL_PREFIXES.some((p) => normalized.startsWith(p));\n\n if (isDdl) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `[dry-run] SQL preview (DDL cannot be validated via EXPLAIN):\\n${sql}`,\n },\n ],\n };\n }\n\n try {\n const [rows] = await runner.query(`EXPLAIN ${sql}`);\n return {\n content: [\n {\n type: 'text' as const,\n text: `[dry-run] Statement validated via EXPLAIN:\\n${JSON.stringify(rows, null, 2)}`,\n },\n ],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: `[dry-run] Validation failed: ${formatError(error)}` }],\n };\n }\n }\n\n try {\n const [result] = await runner.query(sql);\n const r = result as unknown as Record<string, unknown>;\n return {\n content: [\n { type: 'text' as const, text: `affectedRows: ${r.affectedRows}, changedRows: ${r.changedRows ?? 0}` },\n ],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\n\nexport const listDatabasesToolName = 'list_databases';\n\nexport const listDatabasesToolConfig = {\n title: 'List Databases',\n description:\n 'List all databases on the MySQL server. ' +\n 'Use this as a starting point to discover available databases before querying. ' +\n 'Returns a JSON array of database names.',\n};\n\nexport function createListDatabasesHandler(runner: QueryRunner) {\n return async () => {\n try {\n const [rows] = await runner.query('SHOW DATABASES');\n const databases = (rows as Record<string, string>[]).map((r) => Object.values(r)[0]);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(databases) }],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue } from './sql-escape.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const listTablesToolName = 'list_tables';\n\nexport const listTablesToolConfig = {\n title: 'List Tables',\n description:\n 'List all tables in the specified database (or the current database if not specified). ' +\n 'Includes table comments when available. ' +\n 'Use this before describe_table to find the exact table name.',\n inputSchema: {\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n },\n};\n\nexport function createListTablesHandler(runner: QueryRunner) {\n return async ({ database }: { database?: string }) => {\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const sql = `SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = ${quoteStringValue(db)} ORDER BY TABLE_NAME`;\n const [rows] = await query(sql);\n const lines = (rows as Record<string, string>[]).map((r) => {\n const comment = r.TABLE_COMMENT;\n return comment ? `${r.TABLE_NAME} -- ${comment}` : r.TABLE_NAME;\n });\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","type QueryFn = (sql: string) => Promise<[unknown, unknown]>;\n\nexport async function resolveDatabase(query: QueryFn, database?: string): Promise<string | null> {\n if (database) return database;\n const [rows] = await query('SELECT DATABASE() AS db');\n const db = (rows as Record<string, unknown>[])[0]?.db;\n return typeof db === 'string' ? db : null;\n}\n","export function escapeStringValue(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"''\");\n}\n\nexport function quoteStringValue(value: string): string {\n return `'${escapeStringValue(value)}'`;\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue } from './sql-escape.js';\nimport { formatColumn } from './format-column.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const describeTableToolName = 'describe_table';\n\nexport const describeTableToolConfig = {\n title: 'Describe Table',\n description:\n 'Show the schema/structure of a table, including column names, types, constraints, and comments. ' +\n 'Use this before writing queries to ensure correct column names and types. ' +\n 'For inspecting all tables at once, use describe_all_tables instead.',\n inputSchema: {\n table: z.string().describe('Table name to describe.'),\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n },\n};\n\nexport function createDescribeTableHandler(runner: QueryRunner) {\n return async ({ table, database }: { table: string; database?: string }) => {\n const tableValidation = validateIdentifier(table, 'Table');\n if (!tableValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: tableValidation.message! }],\n };\n }\n\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const sql = `SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${quoteStringValue(db)} AND TABLE_NAME = ${quoteStringValue(table)} ORDER BY ORDINAL_POSITION`;\n const [rows] = await query(sql);\n const typedRows = rows as Record<string, unknown>[];\n\n if (typedRows.length === 0) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: `Error: Table '${table}' doesn't exist in database '${db}'.\\nHint: use list_tables to check available tables.`,\n },\n ],\n };\n }\n\n const columns = typedRows.map((r) =>\n formatColumn({\n name: String(r.COLUMN_NAME),\n type: String(r.COLUMN_TYPE),\n nullable: r.IS_NULLABLE === 'YES',\n key: String(r.COLUMN_KEY ?? ''),\n defaultValue: r.COLUMN_DEFAULT,\n extra: String(r.EXTRA ?? ''),\n comment: String(r.COLUMN_COMMENT ?? ''),\n }),\n );\n return {\n content: [{ type: 'text' as const, text: `${table}:\\n${columns.join('\\n')}` }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","export interface ColumnInfo {\n name: string;\n type: string;\n nullable: boolean;\n key: string;\n defaultValue: unknown;\n extra: string;\n comment: string;\n}\n\nexport function formatColumn(col: ColumnInfo): string {\n let result = `${col.name} ${col.type}`;\n if (!col.nullable) result += ' NOT NULL';\n if (col.key === 'PRI') result += ' PK';\n else if (col.key === 'UNI') result += ' UNIQUE';\n else if (col.key === 'MUL') result += ' INDEX';\n if (col.defaultValue != null) result += ` DEFAULT ${col.defaultValue}`;\n if (col.extra) result += ` ${col.extra}`;\n if (col.comment) result += ` -- ${col.comment}`;\n return result;\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue } from './sql-escape.js';\nimport { formatColumn } from './format-column.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const describeAllTablesToolName = 'describe_all_tables';\n\nexport const describeAllTablesToolConfig = {\n title: 'Describe All Tables',\n description:\n 'Show the schema of all tables at once. Much more efficient than calling describe_table for each table individually. ' +\n 'Warning: response can be large for databases with many tables — prefer describe_table for specific tables when possible.',\n inputSchema: {\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n },\n};\n\nexport function createDescribeAllTablesHandler(runner: QueryRunner) {\n return async ({ database }: { database?: string }) => {\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const sql = `SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${quoteStringValue(db)} ORDER BY TABLE_NAME, ORDINAL_POSITION`;\n const [rows] = await query(sql);\n const typedRows = rows as Record<string, unknown>[];\n\n if (typedRows.length === 0) {\n return { content: [{ type: 'text' as const, text: '(no tables)' }] };\n }\n\n const tableMap = new Map<string, string[]>();\n for (const r of typedRows) {\n const tableName = String(r.TABLE_NAME);\n const line = formatColumn({\n name: String(r.COLUMN_NAME),\n type: String(r.COLUMN_TYPE),\n nullable: r.IS_NULLABLE === 'YES',\n key: String(r.COLUMN_KEY ?? ''),\n defaultValue: r.COLUMN_DEFAULT,\n extra: String(r.EXTRA ?? ''),\n comment: String(r.COLUMN_COMMENT ?? ''),\n });\n if (!tableMap.has(tableName)) {\n tableMap.set(tableName, []);\n }\n tableMap.get(tableName)!.push(line);\n }\n\n const parts = Array.from(tableMap.entries()).map(([table, lines]) => `${table}:\\n${lines.join('\\n')}`);\n\n return {\n content: [{ type: 'text' as const, text: parts.join('\\n\\n') }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue, escapeStringValue } from './sql-escape.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const addCommentToolName = 'add_comment';\n\nexport const addCommentToolConfig = {\n title: 'Add Comment',\n description:\n 'Safely add a comment to a table or column. This tool only modifies comments — it cannot alter table structure, column types, or data. ' +\n 'Set dryRun=true to preview the generated SQL without executing it. ' +\n 'Use describe_table first to verify column names. Not available in read-only mode.',\n inputSchema: {\n table: z.string().describe('Table name.'),\n column: z.string().optional().describe('Column name. If omitted, sets a table-level comment.'),\n comment: z.string().describe('Comment text to set.'),\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n dryRun: z\n .boolean()\n .optional()\n .describe('If true, returns the generated SQL without executing it. Defaults to false.'),\n },\n};\n\nexport function createAddCommentHandler(runner: QueryRunner, isReadonly: boolean) {\n return async ({\n table,\n column,\n comment,\n database,\n dryRun,\n }: {\n table: string;\n column?: string;\n comment: string;\n database?: string;\n dryRun?: boolean;\n }) => {\n if (isReadonly) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Server is in read-only mode. Modifying comments is not allowed.',\n },\n ],\n };\n }\n\n const tableValidation = validateIdentifier(table, 'Table');\n if (!tableValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: tableValidation.message! }],\n };\n }\n\n if (column) {\n const columnValidation = validateIdentifier(column, 'Column');\n if (!columnValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: columnValidation.message! }],\n };\n }\n }\n\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const fullName = `\\`${db}\\`.\\`${table}\\``;\n const escapedComment = escapeStringValue(comment);\n\n if (!column) {\n const sql = `ALTER TABLE ${fullName} COMMENT = '${escapedComment}'`;\n if (dryRun) {\n return {\n content: [{ type: 'text' as const, text: `[dry-run] SQL preview:\\n${sql}` }],\n };\n }\n await query(sql);\n return {\n content: [{ type: 'text' as const, text: `Table comment updated: ${table}` }],\n };\n }\n\n const colSql = `SELECT COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${quoteStringValue(db)} AND TABLE_NAME = ${quoteStringValue(table)} AND COLUMN_NAME = ${quoteStringValue(column)}`;\n const [rows] = await query(colSql);\n const colInfo = (rows as Record<string, unknown>[])[0];\n\n if (!colInfo) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: `Error: Column '${column}' doesn't exist in table '${table}'.\\nHint: use describe_table to check available columns.`,\n },\n ],\n };\n }\n\n let modifySql = `ALTER TABLE ${fullName} MODIFY COLUMN \\`${column}\\` ${colInfo.COLUMN_TYPE}`;\n if (colInfo.IS_NULLABLE === 'NO') modifySql += ' NOT NULL';\n if (colInfo.COLUMN_DEFAULT != null)\n modifySql += ` DEFAULT '${escapeStringValue(String(colInfo.COLUMN_DEFAULT))}'`;\n if (colInfo.EXTRA) modifySql += ` ${colInfo.EXTRA}`;\n modifySql += ` COMMENT '${escapedComment}'`;\n\n if (dryRun) {\n return {\n content: [{ type: 'text' as const, text: `[dry-run] SQL preview:\\n${modifySql}` }],\n };\n }\n\n await query(modifySql);\n return {\n content: [{ type: 'text' as const, text: `Column comment updated: ${table}.${column}` }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { QueryRunner } from '../query-runner.js';\nimport { queryToolName, queryToolConfig, createQueryHandler } from './query.js';\nimport { executeToolName, executeToolConfig, createExecuteHandler } from './execute.js';\nimport { listDatabasesToolName, listDatabasesToolConfig, createListDatabasesHandler } from './list-databases.js';\nimport { listTablesToolName, listTablesToolConfig, createListTablesHandler } from './list-tables.js';\nimport { describeTableToolName, describeTableToolConfig, createDescribeTableHandler } from './describe-table.js';\nimport {\n describeAllTablesToolName,\n describeAllTablesToolConfig,\n createDescribeAllTablesHandler,\n} from './describe-all-tables.js';\nimport { addCommentToolName, addCommentToolConfig, createAddCommentHandler } from './add-comment.js';\n\nexport function registerAllTools(server: McpServer, runner: QueryRunner, readonly: boolean, maxRows: number): void {\n server.tool(\n queryToolName,\n queryToolConfig.description,\n queryToolConfig.inputSchema,\n createQueryHandler(runner, maxRows),\n );\n server.tool(\n executeToolName,\n executeToolConfig.description,\n executeToolConfig.inputSchema,\n createExecuteHandler(runner, readonly),\n );\n server.tool(listDatabasesToolName, listDatabasesToolConfig.description, createListDatabasesHandler(runner));\n server.tool(\n listTablesToolName,\n listTablesToolConfig.description,\n listTablesToolConfig.inputSchema,\n createListTablesHandler(runner),\n );\n server.tool(\n describeTableToolName,\n describeTableToolConfig.description,\n describeTableToolConfig.inputSchema,\n createDescribeTableHandler(runner),\n );\n server.tool(\n describeAllTablesToolName,\n describeAllTablesToolConfig.description,\n describeAllTablesToolConfig.inputSchema,\n createDescribeAllTablesHandler(runner),\n );\n server.tool(\n addCommentToolName,\n addCommentToolConfig.description,\n addCommentToolConfig.inputSchema,\n createAddCommentHandler(runner, readonly),\n );\n}\n"],"mappings":"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","names":["mysql","z","z","z","z","z","z","z","z","z","z","require"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/connection.ts","../src/query-runner.ts","../src/server.ts","../src/tools/query.ts","../src/tools/error-hint.ts","../src/tools/validate-input.ts","../src/tools/execute.ts","../src/tools/list-databases.ts","../src/tools/list-tables.ts","../src/tools/resolve-database.ts","../src/tools/sql-escape.ts","../src/tools/describe-table.ts","../src/tools/format-column.ts","../src/tools/describe-all-tables.ts","../src/tools/add-comment.ts","../src/tools/index.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { parseArgs, resolveConfig } from './config.js';\nimport { createConnectionManager } from './connection.js';\nimport { createQueryRunner } from './query-runner.js';\nimport { createMcpServer } from './server.js';\nimport { createRequire } from 'module';\n\nconst HELP_TEXT = `Usage: mysql-mcp-server [options] [mysql://user:pass@host:port/db]\n\nMySQL MCP Server - Model Context Protocol server for MySQL database operations\n\nOptions:\n --readonly Enable read-only mode (blocks execute and add_comment)\n --help, -h Show this help message\n --version Show version number\n\nEnvironment variables:\n MYSQL_HOST MySQL host (required if no connection string)\n MYSQL_PORT MySQL port (default: 3306)\n MYSQL_USER MySQL user (required if no connection string)\n MYSQL_PASSWORD MySQL password (required if no connection string)\n MYSQL_DATABASE Default database\n MYSQL_READONLY Read-only mode (true/false)\n MYSQL_MAX_ROWS Max rows for SELECT queries (default: 100)\n MYSQL_QUERY_TIMEOUT Query timeout in ms (default: 30000, 0 to disable)\n MYSQL_SSL Enable SSL (true/false)\n\nExamples:\n mysql-mcp-server mysql://root:pass@localhost:3306/mydb\n mysql-mcp-server --readonly\n MYSQL_HOST=localhost MYSQL_USER=root MYSQL_PASSWORD=pass mysql-mcp-server`;\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2));\n\n if (args.help) {\n console.log(HELP_TEXT);\n process.exit(0);\n }\n\n if (args.version) {\n const require = createRequire(import.meta.url);\n const pkg = require('../package.json') as { version: string };\n console.log(pkg.version);\n process.exit(0);\n }\n\n const config = resolveConfig(process.argv.slice(2));\n const connectionManager = createConnectionManager(config.mysql, { ssl: config.ssl });\n const runner = createQueryRunner(connectionManager.getPool(), {\n readonly: config.readonly,\n queryTimeout: config.queryTimeout,\n });\n\n const server = createMcpServer(runner, config.readonly, config.maxRows);\n const transport = new StdioServerTransport();\n\n const shutdown = async () => {\n await server.close();\n await connectionManager.close();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n process.stdin.on('end', shutdown);\n\n console.error('MySQL MCP Server starting...');\n console.error(`Readonly mode: ${config.readonly}`);\n console.error(`Query timeout: ${config.queryTimeout}ms`);\n console.error(`SSL: ${config.ssl}`);\n\n await server.connect(transport);\n console.error('MySQL MCP Server connected via stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n});\n","export interface MySQLConfig {\n host: string;\n port: number;\n user: string;\n password: string;\n database?: string;\n}\n\nexport interface AppConfig {\n mysql: MySQLConfig;\n readonly: boolean;\n maxRows: number;\n queryTimeout: number;\n ssl: boolean;\n}\n\nexport function parseConnectionString(connStr: string): MySQLConfig {\n let url: URL;\n try {\n url = new URL(connStr);\n } catch {\n throw new Error(`Invalid connection string: ${connStr}`);\n }\n\n if (url.protocol !== 'mysql:') {\n throw new Error(`Expected mysql:// protocol, got ${url.protocol}`);\n }\n\n const database = url.pathname.slice(1) || undefined;\n\n return {\n host: url.hostname,\n port: url.port ? parseInt(url.port, 10) : 3306,\n user: decodeURIComponent(url.username),\n password: decodeURIComponent(url.password),\n database,\n };\n}\n\nexport function parseEnvConfig(env: Record<string, string | undefined>): MySQLConfig {\n const host = env.MYSQL_HOST;\n const user = env.MYSQL_USER;\n const password = env.MYSQL_PASSWORD;\n\n if (!host) throw new Error('Missing required environment variable: MYSQL_HOST');\n if (!user) throw new Error('Missing required environment variable: MYSQL_USER');\n if (!password) throw new Error('Missing required environment variable: MYSQL_PASSWORD');\n\n return {\n host,\n port: env.MYSQL_PORT ? parseInt(env.MYSQL_PORT, 10) : 3306,\n user,\n password,\n database: env.MYSQL_DATABASE || undefined,\n };\n}\n\nexport interface ParsedArgs {\n connectionString?: string;\n readonly: boolean;\n help: boolean;\n version: boolean;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n let connectionString: string | undefined;\n let readonly = false;\n let help = false;\n let version = false;\n\n for (const arg of argv) {\n if (arg === '--readonly') {\n readonly = true;\n } else if (arg === '--help' || arg === '-h') {\n help = true;\n } else if (arg === '--version') {\n version = true;\n } else if (arg.startsWith('mysql://')) {\n connectionString = arg;\n }\n }\n\n return { connectionString, readonly, help, version };\n}\n\nexport function resolveConfig(argv: string[], env: Record<string, string | undefined> = process.env): AppConfig {\n const args = parseArgs(argv);\n\n const mysql = args.connectionString ? parseConnectionString(args.connectionString) : parseEnvConfig(env);\n\n const readonly = args.readonly || env.MYSQL_READONLY === 'true';\n const maxRows = env.MYSQL_MAX_ROWS ? parseInt(env.MYSQL_MAX_ROWS, 10) : 100;\n const queryTimeout = env.MYSQL_QUERY_TIMEOUT !== undefined ? parseInt(env.MYSQL_QUERY_TIMEOUT, 10) : 30000;\n const ssl = env.MYSQL_SSL === 'true';\n\n return { mysql, readonly, maxRows, queryTimeout, ssl };\n}\n","import mysql from 'mysql2/promise';\nimport type { Pool } from 'mysql2/promise';\nimport type { MySQLConfig } from './config.js';\n\nexport interface ConnectionManager {\n getPool(): Pool;\n close(): Promise<void>;\n}\n\nexport interface ConnectionOptions {\n ssl?: boolean;\n}\n\nexport function createConnectionManager(config: MySQLConfig, options?: ConnectionOptions): ConnectionManager {\n const poolOptions: mysql.PoolOptions = {\n host: config.host,\n port: config.port,\n user: config.user,\n password: config.password,\n database: config.database,\n connectionLimit: 5,\n waitForConnections: true,\n };\n\n if (options?.ssl) {\n poolOptions.ssl = { rejectUnauthorized: true };\n }\n\n const pool = mysql.createPool(poolOptions);\n\n return {\n getPool() {\n return pool;\n },\n async close() {\n await pool.end();\n },\n };\n}\n","import type { Pool } from 'mysql2/promise';\n\ntype QueryFn = (sql: string) => Promise<[unknown, unknown]>;\n\nexport interface QueryRunner {\n query(sql: string): Promise<[unknown, unknown]>;\n withConnection<T>(fn: (query: QueryFn) => Promise<T>): Promise<T>;\n}\n\nexport class QueryTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`Query timeout after ${timeoutMs}ms`);\n this.name = 'QueryTimeoutError';\n }\n}\n\nexport interface QueryRunnerOptions {\n readonly: boolean;\n queryTimeout: number;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {\n if (timeoutMs <= 0) return promise;\n\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => setTimeout(() => reject(new QueryTimeoutError(timeoutMs)), timeoutMs)),\n ]);\n}\n\nexport function createQueryRunner(pool: Pool, options: QueryRunnerOptions): QueryRunner {\n const { readonly, queryTimeout } = options;\n\n return {\n async query(sql: string): Promise<[unknown, unknown]> {\n if (!readonly) {\n return withTimeout(pool.query(sql) as Promise<[unknown, unknown]>, queryTimeout);\n }\n\n const conn = await pool.getConnection();\n try {\n await conn.query('SET SESSION TRANSACTION READ ONLY');\n await conn.beginTransaction();\n const result = await withTimeout(conn.query(sql) as Promise<[unknown, unknown]>, queryTimeout);\n await conn.rollback();\n return result;\n } catch (error) {\n try {\n await conn.rollback();\n } catch {\n // rollback 실패 무시\n }\n throw error;\n } finally {\n conn.release();\n }\n },\n\n async withConnection<T>(fn: (query: QueryFn) => Promise<T>): Promise<T> {\n const conn = await pool.getConnection();\n try {\n if (readonly) {\n await conn.query('SET SESSION TRANSACTION READ ONLY');\n await conn.beginTransaction();\n }\n\n const queryFn: QueryFn = (sql: string) =>\n withTimeout(conn.query(sql) as Promise<[unknown, unknown]>, queryTimeout);\n\n const result = await fn(queryFn);\n\n if (readonly) {\n await conn.rollback();\n }\n\n return result;\n } catch (error) {\n if (readonly) {\n try {\n await conn.rollback();\n } catch {\n // rollback 실패 무시\n }\n }\n throw error;\n } finally {\n conn.release();\n }\n },\n };\n}\n","import { createRequire } from 'module';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { QueryRunner } from './query-runner.js';\nimport { registerAllTools } from './tools/index.js';\n\nexport function createMcpServer(runner: QueryRunner, readonly: boolean, maxRows: number): McpServer {\n const server = new McpServer({\n name: '@imrieul/mysql-mcp-server',\n version: (createRequire(import.meta.url)('../package.json') as { version: string }).version,\n });\n\n registerAllTools(server, runner, readonly, maxRows);\n\n return server;\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { validateSql } from './validate-input.js';\n\nexport const queryToolName = 'query';\n\nexport const queryToolConfig = {\n title: 'Query',\n description:\n 'Execute a read-only SQL query (SELECT, SHOW, DESCRIBE, EXPLAIN). ' +\n 'LIMIT is auto-appended to SELECT/WITH queries without one (default: server maxRows). ' +\n 'Prefer specific columns over SELECT * to reduce response size. ' +\n 'For data modification, use the \"execute\" tool instead.',\n inputSchema: {\n sql: z\n .string()\n .describe(\n 'The SQL query to execute. Only SELECT, SHOW, DESCRIBE, EXPLAIN, and WITH (CTE) statements are allowed.',\n ),\n },\n};\n\nconst ALLOWED_PREFIXES = ['SELECT', 'SHOW', 'DESCRIBE', 'EXPLAIN', 'WITH'];\nconst LIMIT_PREFIXES = ['SELECT', 'WITH'];\n\nfunction needsLimit(normalized: string): boolean {\n if (!LIMIT_PREFIXES.some((p) => normalized.startsWith(p))) return false;\n return !/\\bLIMIT\\b/i.test(normalized);\n}\n\nexport function createQueryHandler(runner: QueryRunner, maxRows: number) {\n return async ({ sql }: { sql: string }) => {\n const validation = validateSql(sql);\n if (!validation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: validation.message! }],\n };\n }\n\n const normalized = sql.trim().toUpperCase();\n const isAllowed = ALLOWED_PREFIXES.some((prefix) => normalized.startsWith(prefix));\n\n if (!isAllowed) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Only SELECT, SHOW, DESCRIBE, EXPLAIN queries are allowed. Use the \"execute\" tool for data modification.',\n },\n ],\n };\n }\n\n try {\n const finalSql = needsLimit(normalized) ? `${sql.trim()} LIMIT ${maxRows}` : sql;\n const [rows] = await runner.query(finalSql);\n const arr = rows as Record<string, unknown>[];\n if (arr.length === 0) {\n return { content: [{ type: 'text' as const, text: '(empty)' }] };\n }\n const cols = Object.keys(arr[0]);\n const data = arr.map((r) => cols.map((c) => r[c]));\n return {\n content: [{ type: 'text' as const, text: JSON.stringify({ columns: cols, rows: data }) }],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","const HINTS: [RegExp, string][] = [\n [/Table '.*' doesn't exist/i, 'Hint: use list_tables to check available tables.'],\n [/Unknown column/i, 'Hint: use describe_table to check column names.'],\n [/Unknown database/i, 'Hint: use list_databases to check available databases.'],\n [/Access denied/i, 'Hint: check database user permissions.'],\n [/ECONNREFUSED|ETIMEDOUT|ENOTFOUND/i, 'Hint: check MYSQL_HOST and MYSQL_PORT settings.'],\n [/ER_PARSE_ERROR/i, 'Hint: check SQL syntax.'],\n [/Query timeout/i, 'Hint: increase MYSQL_QUERY_TIMEOUT or optimize the query.'],\n];\n\nexport function formatError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n const hint = HINTS.find(([pattern]) => pattern.test(message));\n return hint ? `Error: ${message}\\n${hint[1]}` : `Error: ${message}`;\n}\n","/**\n * 에이전트 환각 대비 입력 검증 모듈\n * - 제어문자 거부 (탭/개행/캐리지리턴 제외)\n * - 식별자(테이블/컬럼명) 위험 패턴 거부\n */\n\nfunction hasControlChars(str: string): boolean {\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n // 허용: \\t(9), \\n(10), \\r(13)\n if (code === 9 || code === 10 || code === 13) continue;\n // 제어문자: 0x00-0x1f, 0x7f\n if (code <= 0x1f || code === 0x7f) return true;\n }\n return false;\n}\n\nconst DANGEROUS_IDENTIFIER_PATTERNS = [\n /;/, // SQL statement separator\n /--/, // SQL line comment\n /\\/\\*/, // SQL block comment start\n /\\*\\//, // SQL block comment end\n /\\\\/, // backslash escape\n];\n\nexport interface ValidationResult {\n valid: boolean;\n message?: string;\n}\n\nexport function validateSql(sql: string): ValidationResult {\n if (hasControlChars(sql)) {\n return {\n valid: false,\n message: 'Error: SQL contains control characters. Remove non-printable characters (tab and newline are allowed).',\n };\n }\n return { valid: true };\n}\n\nexport function validateIdentifier(name: string, label: string): ValidationResult {\n if (!name || name.trim().length === 0) {\n return { valid: false, message: `Error: ${label} name cannot be empty.` };\n }\n\n if (hasControlChars(name)) {\n return {\n valid: false,\n message: `Error: ${label} name contains control characters.`,\n };\n }\n\n for (const pattern of DANGEROUS_IDENTIFIER_PATTERNS) {\n if (pattern.test(name)) {\n return {\n valid: false,\n message: `Error: ${label} name contains dangerous characters (${pattern.source}). Use only valid MySQL identifier characters.`,\n };\n }\n }\n\n if (name.length > 64) {\n return {\n valid: false,\n message: `Error: ${label} name exceeds MySQL's 64-character limit.`,\n };\n }\n\n return { valid: true };\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { validateSql } from './validate-input.js';\n\nexport const executeToolName = 'execute';\n\nexport const executeToolConfig = {\n title: 'Execute',\n description:\n 'Execute a data modification SQL statement (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, etc.). ' +\n 'Set dryRun=true to validate without executing — uses EXPLAIN for DML, or previews the SQL for DDL. ' +\n 'Always confirm destructive operations (DROP, TRUNCATE, DELETE without WHERE) with the user before executing. ' +\n 'Not available in read-only mode.',\n inputSchema: {\n sql: z\n .string()\n .describe('The SQL statement to execute. SELECT statements are not allowed here; use the \"query\" tool instead.'),\n dryRun: z\n .boolean()\n .optional()\n .describe('If true, validates the statement via EXPLAIN without executing it. Defaults to false.'),\n },\n};\n\nexport function createExecuteHandler(runner: QueryRunner, isReadonly: boolean) {\n return async ({ sql, dryRun }: { sql: string; dryRun?: boolean }) => {\n if (isReadonly) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Server is in read-only mode. Data modification is not allowed.',\n },\n ],\n };\n }\n\n const validation = validateSql(sql);\n if (!validation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: validation.message! }],\n };\n }\n\n const normalized = sql.trim().toUpperCase();\n if (normalized.startsWith('SELECT') || normalized.startsWith('WITH')) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Use the \"query\" tool for SELECT statements.',\n },\n ],\n };\n }\n\n if (dryRun) {\n const DDL_PREFIXES = ['CREATE', 'DROP', 'ALTER', 'TRUNCATE', 'RENAME'];\n const isDdl = DDL_PREFIXES.some((p) => normalized.startsWith(p));\n\n if (isDdl) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `[dry-run] SQL preview (DDL cannot be validated via EXPLAIN):\\n${sql}`,\n },\n ],\n };\n }\n\n try {\n const [rows] = await runner.query(`EXPLAIN ${sql}`);\n return {\n content: [\n {\n type: 'text' as const,\n text: `[dry-run] Statement validated via EXPLAIN:\\n${JSON.stringify(rows, null, 2)}`,\n },\n ],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: `[dry-run] Validation failed: ${formatError(error)}` }],\n };\n }\n }\n\n try {\n const [result] = await runner.query(sql);\n const r = result as unknown as Record<string, unknown>;\n return {\n content: [\n { type: 'text' as const, text: `affectedRows: ${r.affectedRows}, changedRows: ${r.changedRows ?? 0}` },\n ],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\n\nexport const listDatabasesToolName = 'list_databases';\n\nexport const listDatabasesToolConfig = {\n title: 'List Databases',\n description:\n 'List all databases on the MySQL server. ' +\n 'Use this as a starting point to discover available databases before querying. ' +\n 'Returns a JSON array of database names.',\n};\n\nexport function createListDatabasesHandler(runner: QueryRunner) {\n return async () => {\n try {\n const [rows] = await runner.query('SHOW DATABASES');\n const databases = (rows as Record<string, string>[]).map((r) => Object.values(r)[0]);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(databases) }],\n };\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue } from './sql-escape.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const listTablesToolName = 'list_tables';\n\nexport const listTablesToolConfig = {\n title: 'List Tables',\n description:\n 'List all tables in the specified database (or the current database if not specified). ' +\n 'Includes table comments when available. ' +\n 'Use this before describe_table to find the exact table name.',\n inputSchema: {\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n },\n};\n\nexport function createListTablesHandler(runner: QueryRunner) {\n return async ({ database }: { database?: string }) => {\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const sql = `SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = ${quoteStringValue(db)} ORDER BY TABLE_NAME`;\n const [rows] = await query(sql);\n const lines = (rows as Record<string, string>[]).map((r) => {\n const comment = r.TABLE_COMMENT;\n return comment ? `${r.TABLE_NAME} -- ${comment}` : r.TABLE_NAME;\n });\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","type QueryFn = (sql: string) => Promise<[unknown, unknown]>;\n\nexport async function resolveDatabase(query: QueryFn, database?: string): Promise<string | null> {\n if (database) return database;\n const [rows] = await query('SELECT DATABASE() AS db');\n const db = (rows as Record<string, unknown>[])[0]?.db;\n return typeof db === 'string' ? db : null;\n}\n","export function escapeStringValue(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"''\");\n}\n\nexport function quoteStringValue(value: string): string {\n return `'${escapeStringValue(value)}'`;\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue } from './sql-escape.js';\nimport { formatColumn } from './format-column.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const describeTableToolName = 'describe_table';\n\nexport const describeTableToolConfig = {\n title: 'Describe Table',\n description:\n 'Show the schema/structure of a table, including column names, types, constraints, and comments. ' +\n 'Use this before writing queries to ensure correct column names and types. ' +\n 'For inspecting all tables at once, use describe_all_tables instead.',\n inputSchema: {\n table: z.string().describe('Table name to describe.'),\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n },\n};\n\nexport function createDescribeTableHandler(runner: QueryRunner) {\n return async ({ table, database }: { table: string; database?: string }) => {\n const tableValidation = validateIdentifier(table, 'Table');\n if (!tableValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: tableValidation.message! }],\n };\n }\n\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const sql = `SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${quoteStringValue(db)} AND TABLE_NAME = ${quoteStringValue(table)} ORDER BY ORDINAL_POSITION`;\n const [rows] = await query(sql);\n const typedRows = rows as Record<string, unknown>[];\n\n if (typedRows.length === 0) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: `Error: Table '${table}' doesn't exist in database '${db}'.\\nHint: use list_tables to check available tables.`,\n },\n ],\n };\n }\n\n const columns = typedRows.map((r) =>\n formatColumn({\n name: String(r.COLUMN_NAME),\n type: String(r.COLUMN_TYPE),\n nullable: r.IS_NULLABLE === 'YES',\n key: String(r.COLUMN_KEY ?? ''),\n defaultValue: r.COLUMN_DEFAULT,\n extra: String(r.EXTRA ?? ''),\n comment: String(r.COLUMN_COMMENT ?? ''),\n }),\n );\n return {\n content: [{ type: 'text' as const, text: `${table}:\\n${columns.join('\\n')}` }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","export interface ColumnInfo {\n name: string;\n type: string;\n nullable: boolean;\n key: string;\n defaultValue: unknown;\n extra: string;\n comment: string;\n}\n\nexport function formatColumn(col: ColumnInfo): string {\n let result = `${col.name} ${col.type}`;\n if (!col.nullable) result += ' NOT NULL';\n if (col.key === 'PRI') result += ' PK';\n else if (col.key === 'UNI') result += ' UNIQUE';\n else if (col.key === 'MUL') result += ' INDEX';\n if (col.defaultValue != null) result += ` DEFAULT ${col.defaultValue}`;\n if (col.extra) result += ` ${col.extra}`;\n if (col.comment) result += ` -- ${col.comment}`;\n return result;\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue } from './sql-escape.js';\nimport { formatColumn } from './format-column.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const describeAllTablesToolName = 'describe_all_tables';\n\nexport const describeAllTablesToolConfig = {\n title: 'Describe All Tables',\n description:\n 'Show the schema of all tables at once. Much more efficient than calling describe_table for each table individually. ' +\n 'Warning: response can be large for databases with many tables — prefer describe_table for specific tables when possible.',\n inputSchema: {\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n },\n};\n\nexport function createDescribeAllTablesHandler(runner: QueryRunner) {\n return async ({ database }: { database?: string }) => {\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const sql = `SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${quoteStringValue(db)} ORDER BY TABLE_NAME, ORDINAL_POSITION`;\n const [rows] = await query(sql);\n const typedRows = rows as Record<string, unknown>[];\n\n if (typedRows.length === 0) {\n return { content: [{ type: 'text' as const, text: '(no tables)' }] };\n }\n\n const tableMap = new Map<string, string[]>();\n for (const r of typedRows) {\n const tableName = String(r.TABLE_NAME);\n const line = formatColumn({\n name: String(r.COLUMN_NAME),\n type: String(r.COLUMN_TYPE),\n nullable: r.IS_NULLABLE === 'YES',\n key: String(r.COLUMN_KEY ?? ''),\n defaultValue: r.COLUMN_DEFAULT,\n extra: String(r.EXTRA ?? ''),\n comment: String(r.COLUMN_COMMENT ?? ''),\n });\n if (!tableMap.has(tableName)) {\n tableMap.set(tableName, []);\n }\n tableMap.get(tableName)!.push(line);\n }\n\n const parts = Array.from(tableMap.entries()).map(([table, lines]) => `${table}:\\n${lines.join('\\n')}`);\n\n return {\n content: [{ type: 'text' as const, text: parts.join('\\n\\n') }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import { z } from 'zod';\nimport type { QueryRunner } from '../query-runner.js';\nimport { formatError } from './error-hint.js';\nimport { resolveDatabase } from './resolve-database.js';\nimport { quoteStringValue, escapeStringValue } from './sql-escape.js';\nimport { validateIdentifier } from './validate-input.js';\n\nexport const addCommentToolName = 'add_comment';\n\nexport const addCommentToolConfig = {\n title: 'Add Comment',\n description:\n 'Safely add a comment to a table or column. This tool only modifies comments — it cannot alter table structure, column types, or data. ' +\n 'Set dryRun=true to preview the generated SQL without executing it. ' +\n 'Use describe_table first to verify column names. Not available in read-only mode.',\n inputSchema: {\n table: z.string().describe('Table name.'),\n column: z.string().optional().describe('Column name. If omitted, sets a table-level comment.'),\n comment: z.string().describe('Comment text to set.'),\n database: z.string().optional().describe('Database name. Uses the current database if omitted.'),\n dryRun: z\n .boolean()\n .optional()\n .describe('If true, returns the generated SQL without executing it. Defaults to false.'),\n },\n};\n\nexport function createAddCommentHandler(runner: QueryRunner, isReadonly: boolean) {\n return async ({\n table,\n column,\n comment,\n database,\n dryRun,\n }: {\n table: string;\n column?: string;\n comment: string;\n database?: string;\n dryRun?: boolean;\n }) => {\n if (isReadonly) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: Server is in read-only mode. Modifying comments is not allowed.',\n },\n ],\n };\n }\n\n const tableValidation = validateIdentifier(table, 'Table');\n if (!tableValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: tableValidation.message! }],\n };\n }\n\n if (column) {\n const columnValidation = validateIdentifier(column, 'Column');\n if (!columnValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: columnValidation.message! }],\n };\n }\n }\n\n if (database) {\n const dbValidation = validateIdentifier(database, 'Database');\n if (!dbValidation.valid) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: dbValidation.message! }],\n };\n }\n }\n\n try {\n return await runner.withConnection(async (query) => {\n const db = await resolveDatabase(query, database);\n if (!db) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',\n },\n ],\n };\n }\n\n const fullName = `\\`${db}\\`.\\`${table}\\``;\n const escapedComment = escapeStringValue(comment);\n\n if (!column) {\n const sql = `ALTER TABLE ${fullName} COMMENT = '${escapedComment}'`;\n if (dryRun) {\n return {\n content: [{ type: 'text' as const, text: `[dry-run] SQL preview:\\n${sql}` }],\n };\n }\n await query(sql);\n return {\n content: [{ type: 'text' as const, text: `Table comment updated: ${table}` }],\n };\n }\n\n const colSql = `SELECT COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${quoteStringValue(db)} AND TABLE_NAME = ${quoteStringValue(table)} AND COLUMN_NAME = ${quoteStringValue(column)}`;\n const [rows] = await query(colSql);\n const colInfo = (rows as Record<string, unknown>[])[0];\n\n if (!colInfo) {\n return {\n isError: true as const,\n content: [\n {\n type: 'text' as const,\n text: `Error: Column '${column}' doesn't exist in table '${table}'.\\nHint: use describe_table to check available columns.`,\n },\n ],\n };\n }\n\n let modifySql = `ALTER TABLE ${fullName} MODIFY COLUMN \\`${column}\\` ${colInfo.COLUMN_TYPE}`;\n if (colInfo.IS_NULLABLE === 'NO') modifySql += ' NOT NULL';\n if (colInfo.COLUMN_DEFAULT != null)\n modifySql += ` DEFAULT '${escapeStringValue(String(colInfo.COLUMN_DEFAULT))}'`;\n if (colInfo.EXTRA) modifySql += ` ${colInfo.EXTRA}`;\n modifySql += ` COMMENT '${escapedComment}'`;\n\n if (dryRun) {\n return {\n content: [{ type: 'text' as const, text: `[dry-run] SQL preview:\\n${modifySql}` }],\n };\n }\n\n await query(modifySql);\n return {\n content: [{ type: 'text' as const, text: `Column comment updated: ${table}.${column}` }],\n };\n });\n } catch (error) {\n return {\n isError: true as const,\n content: [{ type: 'text' as const, text: formatError(error) }],\n };\n }\n };\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { QueryRunner } from '../query-runner.js';\nimport { queryToolName, queryToolConfig, createQueryHandler } from './query.js';\nimport { executeToolName, executeToolConfig, createExecuteHandler } from './execute.js';\nimport { listDatabasesToolName, listDatabasesToolConfig, createListDatabasesHandler } from './list-databases.js';\nimport { listTablesToolName, listTablesToolConfig, createListTablesHandler } from './list-tables.js';\nimport { describeTableToolName, describeTableToolConfig, createDescribeTableHandler } from './describe-table.js';\nimport {\n describeAllTablesToolName,\n describeAllTablesToolConfig,\n createDescribeAllTablesHandler,\n} from './describe-all-tables.js';\nimport { addCommentToolName, addCommentToolConfig, createAddCommentHandler } from './add-comment.js';\n\nexport function registerAllTools(server: McpServer, runner: QueryRunner, readonly: boolean, maxRows: number): void {\n server.tool(\n queryToolName,\n queryToolConfig.description,\n queryToolConfig.inputSchema,\n createQueryHandler(runner, maxRows),\n );\n server.tool(\n executeToolName,\n executeToolConfig.description,\n executeToolConfig.inputSchema,\n createExecuteHandler(runner, readonly),\n );\n server.tool(listDatabasesToolName, listDatabasesToolConfig.description, createListDatabasesHandler(runner));\n server.tool(\n listTablesToolName,\n listTablesToolConfig.description,\n listTablesToolConfig.inputSchema,\n createListTablesHandler(runner),\n );\n server.tool(\n describeTableToolName,\n describeTableToolConfig.description,\n describeTableToolConfig.inputSchema,\n createDescribeTableHandler(runner),\n );\n server.tool(\n describeAllTablesToolName,\n describeAllTablesToolConfig.description,\n describeAllTablesToolConfig.inputSchema,\n createDescribeAllTablesHandler(runner),\n );\n server.tool(\n addCommentToolName,\n addCommentToolConfig.description,\n addCommentToolConfig.inputSchema,\n createAddCommentHandler(runner, readonly),\n );\n}\n"],"mappings":"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","names":["mysql","z","z","z","z","z","z","z","z","z","z","createRequire","require"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imrieul/mysql-mcp-server",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "MySQL MCP Server - Simple Model Context Protocol server for MySQL database operations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -45,14 +45,14 @@
45
45
  },
46
46
  "license": "MIT",
47
47
  "dependencies": {
48
- "@modelcontextprotocol/sdk": "^1.25.0",
49
- "mysql2": "^3.11.0",
48
+ "@modelcontextprotocol/sdk": "^1.30.0",
49
+ "mysql2": "^3.24.4",
50
50
  "zod": "^3.25.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@eslint/js": "^9.39.2",
54
54
  "@types/node": "^18.19.130",
55
- "@vitest/coverage-v8": "^2.1.9",
55
+ "@vitest/coverage-v8": "^3.2.7",
56
56
  "eslint": "^9.39.2",
57
57
  "eslint-config-prettier": "^10.1.8",
58
58
  "husky": "^9.1.7",
@@ -62,7 +62,7 @@
62
62
  "tsup": "^8.0.0",
63
63
  "typescript": "^5.5.0",
64
64
  "typescript-eslint": "^8.54.0",
65
- "vitest": "^2.0.0"
65
+ "vitest": "^3.2.7"
66
66
  },
67
67
  "engines": {
68
68
  "node": ">=18"
package/README.es.md DELETED
@@ -1,150 +0,0 @@
1
- # @imrieul/mysql-mcp-server
2
-
3
- [English](./README.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md) | [中文](./README.zh.md) | [Português](./README.pt.md) | [Français](./README.fr.md) | [Русский](./README.ru.md)
4
-
5
- Un servidor [MCP](https://modelcontextprotocol.io/) simple para MySQL.
6
-
7
- ## Características
8
-
9
- - **Optimizado para LLM** — formato compacto de columnas/filas, LIMIT automático, sugerencias de error con acciones sugeridas
10
- - **Esquema en bloque** — `describe_all_tables` devuelve todo el esquema de la base de datos en una sola llamada
11
- - **Modo de solo lectura** — verificación de prefijo a nivel de aplicación + `SET SESSION TRANSACTION READ ONLY` a nivel de base de datos
12
- - **Tiempo de espera de consultas** — tiempo de espera basado en `Promise.race()` con limpieza de conexión garantizada
13
- - **Soporte SSL** — una variable de entorno para habilitar conexiones cifradas
14
- - **Minimalista** — 3 dependencias, sin configuración requerida
15
-
16
- ## Inicio Rápido
17
-
18
- Añade a tu configuración MCP (`.mcp.json` o `claude_desktop_config.json`):
19
-
20
- ```json
21
- {
22
- "mcpServers": {
23
- "mysql": {
24
- "command": "npx",
25
- "args": ["-y", "@imrieul/mysql-mcp-server"],
26
- "env": {
27
- "MYSQL_HOST": "localhost",
28
- "MYSQL_PORT": "3306",
29
- "MYSQL_USER": "root",
30
- "MYSQL_PASSWORD": "your-password",
31
- "MYSQL_DATABASE": "your-database"
32
- }
33
- }
34
- }
35
- }
36
- ```
37
-
38
- O con una cadena de conexión:
39
-
40
- ```json
41
- {
42
- "mcpServers": {
43
- "mysql": {
44
- "command": "npx",
45
- "args": ["-y", "@imrieul/mysql-mcp-server", "mysql://root:password@localhost:3306/mydb"]
46
- }
47
- }
48
- }
49
- ```
50
-
51
- ### Codex
52
-
53
- Codex usa configuración TOML, no JSON con `mcpServers`. Añade esto a `~/.codex/config.toml` o a un `.codex/config.toml` con alcance de proyecto:
54
-
55
- ```toml
56
- [mcp_servers.mysql]
57
- command = "npx"
58
- args = ["-y", "@imrieul/mysql-mcp-server"]
59
-
60
- [mcp_servers.mysql.env]
61
- MYSQL_HOST = "localhost"
62
- MYSQL_PORT = "3306"
63
- MYSQL_USER = "root"
64
- MYSQL_PASSWORD = "your-password"
65
- MYSQL_DATABASE = "your-database"
66
- ```
67
-
68
- ### opencode
69
-
70
- Añade esto a `opencode.json` u `opencode.jsonc`:
71
-
72
- ```json
73
- {
74
- "$schema": "https://opencode.ai/config.json",
75
- "mcp": {
76
- "mysql": {
77
- "type": "local",
78
- "command": ["npx", "-y", "@imrieul/mysql-mcp-server"],
79
- "enabled": true,
80
- "environment": {
81
- "MYSQL_HOST": "localhost",
82
- "MYSQL_PORT": "3306",
83
- "MYSQL_USER": "root",
84
- "MYSQL_PASSWORD": "your-password",
85
- "MYSQL_DATABASE": "your-database"
86
- }
87
- }
88
- }
89
- }
90
- ```
91
-
92
- ### Modo de solo lectura con SSL
93
-
94
- ```json
95
- {
96
- "mcpServers": {
97
- "mysql": {
98
- "command": "npx",
99
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
100
- "env": {
101
- "MYSQL_HOST": "db.example.com",
102
- "MYSQL_USER": "readonly_user",
103
- "MYSQL_PASSWORD": "password",
104
- "MYSQL_DATABASE": "production",
105
- "MYSQL_SSL": "true",
106
- "MYSQL_QUERY_TIMEOUT": "10000"
107
- }
108
- }
109
- }
110
- }
111
- ```
112
-
113
- ## Herramientas
114
-
115
- | Tool | Descripción | Modo de solo lectura |
116
- |------|-------------|----------------------|
117
- | `query` | Ejecutar SELECT, SHOW, DESCRIBE, EXPLAIN | Permitido |
118
- | `execute` | Ejecutar INSERT, UPDATE, DELETE, DDL | Bloqueado |
119
- | `list_databases` | Listar todas las bases de datos | Permitido |
120
- | `list_tables` | Listar tablas en una base de datos | Permitido |
121
- | `describe_table` | Mostrar esquema de tabla | Permitido |
122
- | `describe_all_tables` | Mostrar todos los esquemas de tabla a la vez | Permitido |
123
-
124
- ## Configuración
125
-
126
- ### Variables de entorno
127
-
128
- | Variable | Requerida | Por defecto | Descripción |
129
- |----------|-----------|-------------|-------------|
130
- | `MYSQL_HOST` | Sí | — | Host de MySQL |
131
- | `MYSQL_USER` | Sí | — | Usuario de MySQL |
132
- | `MYSQL_PASSWORD` | Sí | — | Contraseña de MySQL |
133
- | `MYSQL_PORT` | No | `3306` | Puerto de MySQL |
134
- | `MYSQL_DATABASE` | No | — | Base de datos por defecto |
135
- | `MYSQL_READONLY` | No | `false` | Modo de solo lectura |
136
- | `MYSQL_MAX_ROWS` | No | `100` | LIMIT automático para consultas SELECT |
137
- | `MYSQL_QUERY_TIMEOUT` | No | `30000` | Tiempo de espera de consulta en ms (0 para deshabilitar) |
138
- | `MYSQL_SSL` | No | `false` | Habilitar conexión SSL |
139
-
140
- ### Cadena de conexión
141
-
142
- ```
143
- mysql://user:password@host:port/database
144
- ```
145
-
146
- Se pasa como el primer argumento CLI. Tiene prioridad sobre las variables de entorno.
147
-
148
- ## Licencia
149
-
150
- MIT