@imrieul/mysql-mcp-server 1.1.0 → 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
 
@@ -48,6 +48,47 @@ Or with a connection string:
48
48
  }
49
49
  ```
50
50
 
51
+ ### Codex
52
+
53
+ Codex uses TOML config, not `mcpServers` JSON. Add this to `~/.codex/config.toml` or a project-scoped `.codex/config.toml`:
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
+ Add this to `opencode.json` or `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
+
51
92
  ### Read-only mode with SSL
52
93
 
53
94
  ```json
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.0",
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,109 +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
- ### Modo de solo lectura con SSL
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "mysql": {
57
- "command": "npx",
58
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
59
- "env": {
60
- "MYSQL_HOST": "db.example.com",
61
- "MYSQL_USER": "readonly_user",
62
- "MYSQL_PASSWORD": "password",
63
- "MYSQL_DATABASE": "production",
64
- "MYSQL_SSL": "true",
65
- "MYSQL_QUERY_TIMEOUT": "10000"
66
- }
67
- }
68
- }
69
- }
70
- ```
71
-
72
- ## Herramientas
73
-
74
- | Tool | Descripción | Modo de solo lectura |
75
- |------|-------------|----------------------|
76
- | `query` | Ejecutar SELECT, SHOW, DESCRIBE, EXPLAIN | Permitido |
77
- | `execute` | Ejecutar INSERT, UPDATE, DELETE, DDL | Bloqueado |
78
- | `list_databases` | Listar todas las bases de datos | Permitido |
79
- | `list_tables` | Listar tablas en una base de datos | Permitido |
80
- | `describe_table` | Mostrar esquema de tabla | Permitido |
81
- | `describe_all_tables` | Mostrar todos los esquemas de tabla a la vez | Permitido |
82
-
83
- ## Configuración
84
-
85
- ### Variables de entorno
86
-
87
- | Variable | Requerida | Por defecto | Descripción |
88
- |----------|-----------|-------------|-------------|
89
- | `MYSQL_HOST` | Sí | — | Host de MySQL |
90
- | `MYSQL_USER` | Sí | — | Usuario de MySQL |
91
- | `MYSQL_PASSWORD` | Sí | — | Contraseña de MySQL |
92
- | `MYSQL_PORT` | No | `3306` | Puerto de MySQL |
93
- | `MYSQL_DATABASE` | No | — | Base de datos por defecto |
94
- | `MYSQL_READONLY` | No | `false` | Modo de solo lectura |
95
- | `MYSQL_MAX_ROWS` | No | `100` | LIMIT automático para consultas SELECT |
96
- | `MYSQL_QUERY_TIMEOUT` | No | `30000` | Tiempo de espera de consulta en ms (0 para deshabilitar) |
97
- | `MYSQL_SSL` | No | `false` | Habilitar conexión SSL |
98
-
99
- ### Cadena de conexión
100
-
101
- ```
102
- mysql://user:password@host:port/database
103
- ```
104
-
105
- Se pasa como el primer argumento CLI. Tiene prioridad sobre las variables de entorno.
106
-
107
- ## Licencia
108
-
109
- MIT
package/README.fr.md DELETED
@@ -1,109 +0,0 @@
1
- # @imrieul/mysql-mcp-server
2
-
3
- [English](./README.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md) | [中文](./README.zh.md) | [Español](./README.es.md) | [Português](./README.pt.md) | [Русский](./README.ru.md)
4
-
5
- Un serveur [MCP](https://modelcontextprotocol.io/) MySQL simple.
6
-
7
- ## Fonctionnalités
8
-
9
- - **Compatible LLM** — format colonnes/lignes compact, LIMIT automatique, suggestions d'actions suite aux erreurs
10
- - **Schéma en masse** — `describe_all_tables` retourne le schéma complet de la base en un seul appel
11
- - **Mode lecture seule** — vérification au niveau applicatif + `SET SESSION TRANSACTION READ ONLY` au niveau base de données
12
- - **Timeout des requêtes** — timeout basé sur `Promise.race()` avec nettoyage garanti des connexions
13
- - **Support SSL** — une seule variable d'environnement pour activer les connexions chiffrées
14
- - **Minimal** — 3 dépendances, aucune configuration requise
15
-
16
- ## Démarrage rapide
17
-
18
- Ajoutez à votre configuration MCP (`.mcp.json` ou `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
- Ou avec une chaîne de connexion :
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
- ### Mode lecture seule avec SSL
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "mysql": {
57
- "command": "npx",
58
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
59
- "env": {
60
- "MYSQL_HOST": "db.example.com",
61
- "MYSQL_USER": "readonly_user",
62
- "MYSQL_PASSWORD": "password",
63
- "MYSQL_DATABASE": "production",
64
- "MYSQL_SSL": "true",
65
- "MYSQL_QUERY_TIMEOUT": "10000"
66
- }
67
- }
68
- }
69
- }
70
- ```
71
-
72
- ## Outils
73
-
74
- | Outil | Description | Mode lecture seule |
75
- |------|-------------|----------------|
76
- | `query` | Exécuter SELECT, SHOW, DESCRIBE, EXPLAIN | Autorisé |
77
- | `execute` | Exécuter INSERT, UPDATE, DELETE, DDL | Bloqué |
78
- | `list_databases` | Lister toutes les bases de données | Autorisé |
79
- | `list_tables` | Lister les tables d'une base de données | Autorisé |
80
- | `describe_table` | Afficher le schéma d'une table | Autorisé |
81
- | `describe_all_tables` | Afficher tous les schémas de tables en une fois | Autorisé |
82
-
83
- ## Configuration
84
-
85
- ### Variables d'environnement
86
-
87
- | Variable | Requis | Défaut | Description |
88
- |----------|----------|---------|-------------|
89
- | `MYSQL_HOST` | Oui | — | Hôte MySQL |
90
- | `MYSQL_USER` | Oui | — | Utilisateur MySQL |
91
- | `MYSQL_PASSWORD` | Oui | — | Mot de passe MySQL |
92
- | `MYSQL_PORT` | Non | `3306` | Port MySQL |
93
- | `MYSQL_DATABASE` | Non | — | Base de données par défaut |
94
- | `MYSQL_READONLY` | Non | `false` | Mode lecture seule |
95
- | `MYSQL_MAX_ROWS` | Non | `100` | LIMIT automatique pour les requêtes SELECT |
96
- | `MYSQL_QUERY_TIMEOUT` | Non | `30000` | Timeout des requêtes en ms (0 pour désactiver) |
97
- | `MYSQL_SSL` | Non | `false` | Activer la connexion SSL |
98
-
99
- ### Chaîne de connexion
100
-
101
- ```
102
- mysql://user:password@host:port/database
103
- ```
104
-
105
- Passée comme premier argument CLI. Prioritaire sur les variables d'environnement.
106
-
107
- ## Licence
108
-
109
- MIT
package/README.ja.md DELETED
@@ -1,109 +0,0 @@
1
- # @imrieul/mysql-mcp-server
2
-
3
- [English](./README.md) | [한국어](./README.ko.md) | [中文](./README.zh.md) | [Español](./README.es.md) | [Português](./README.pt.md) | [Français](./README.fr.md) | [Русский](./README.ru.md)
4
-
5
- シンプルなMySQL [MCP](https://modelcontextprotocol.io/)サーバーです。
6
-
7
- ## 特徴
8
-
9
- - **LLM最適化** — コンパクトなカラム/行形式、自動LIMIT、次のアクション提案を含むエラーヒント
10
- - **一括スキーマ取得** — `describe_all_tables`で全データベーススキーマを一度に取得
11
- - **読み取り専用モード** — アプリケーションレベルのプレフィックスチェック + データベースレベルの`SET SESSION TRANSACTION READ ONLY`
12
- - **クエリタイムアウト** — `Promise.race()`ベースのタイムアウトと確実なコネクションクリーンアップ
13
- - **SSL対応** — 環境変数1つで暗号化接続を有効化
14
- - **ミニマル** — 依存関係3つ、設定不要
15
-
16
- ## クイックスタート
17
-
18
- MCPの設定ファイル(`.mcp.json`または`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
- 接続文字列を使用する場合:
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
- ### SSLを使用した読み取り専用モード
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "mysql": {
57
- "command": "npx",
58
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
59
- "env": {
60
- "MYSQL_HOST": "db.example.com",
61
- "MYSQL_USER": "readonly_user",
62
- "MYSQL_PASSWORD": "password",
63
- "MYSQL_DATABASE": "production",
64
- "MYSQL_SSL": "true",
65
- "MYSQL_QUERY_TIMEOUT": "10000"
66
- }
67
- }
68
- }
69
- }
70
- ```
71
-
72
- ## ツール
73
-
74
- | Tool | Description | Read-only mode |
75
- |------|-------------|----------------|
76
- | `query` | SELECT, SHOW, DESCRIBE, EXPLAINの実行 | 許可 |
77
- | `execute` | INSERT, UPDATE, DELETE, DDLの実行 | ブロック |
78
- | `list_databases` | 全データベースの一覧表示 | 許可 |
79
- | `list_tables` | データベース内のテーブル一覧表示 | 許可 |
80
- | `describe_table` | テーブルスキーマの表示 | 許可 |
81
- | `describe_all_tables` | 全テーブルスキーマの一括表示 | 許可 |
82
-
83
- ## 設定
84
-
85
- ### 環境変数
86
-
87
- | Variable | Required | Default | Description |
88
- |----------|----------|---------|-------------|
89
- | `MYSQL_HOST` | はい | — | MySQLホスト |
90
- | `MYSQL_USER` | はい | — | MySQLユーザー |
91
- | `MYSQL_PASSWORD` | はい | — | MySQLパスワード |
92
- | `MYSQL_PORT` | いいえ | `3306` | MySQLポート |
93
- | `MYSQL_DATABASE` | いいえ | — | デフォルトデータベース |
94
- | `MYSQL_READONLY` | いいえ | `false` | 読み取り専用モード |
95
- | `MYSQL_MAX_ROWS` | いいえ | `100` | SELECTクエリの自動LIMIT |
96
- | `MYSQL_QUERY_TIMEOUT` | いいえ | `30000` | クエリタイムアウト(ミリ秒、0で無効化) |
97
- | `MYSQL_SSL` | いいえ | `false` | SSL接続を有効化 |
98
-
99
- ### 接続文字列
100
-
101
- ```
102
- mysql://user:password@host:port/database
103
- ```
104
-
105
- 最初のCLI引数として渡されます。環境変数より優先されます。
106
-
107
- ## ライセンス
108
-
109
- MIT
package/README.ko.md DELETED
@@ -1,109 +0,0 @@
1
- # @imrieul/mysql-mcp-server
2
-
3
- [English](./README.md) | [日本語](./README.ja.md) | [中文](./README.zh.md) | [Español](./README.es.md) | [Português](./README.pt.md) | [Français](./README.fr.md) | [Русский](./README.ru.md)
4
-
5
- 간단한 MySQL [MCP](https://modelcontextprotocol.io/) 서버입니다.
6
-
7
- ## 특징
8
-
9
- - **LLM 친화적** — 압축된 컬럼/행 형식, 자동 LIMIT, 다음 작업 제안이 포함된 오류 힌트
10
- - **일괄 스키마 조회** — `describe_all_tables`로 전체 DB 스키마를 한 번에 조회
11
- - **읽기 전용 모드** — 애플리케이션 레벨 접두사 검사 + DB 레벨 `SET SESSION TRANSACTION READ ONLY`
12
- - **쿼리 타임아웃** — `Promise.race()` 기반 타임아웃 및 연결 정리 보장
13
- - **SSL 지원** — 환경 변수 하나로 암호화된 연결 활성화
14
- - **미니멀** — 3개의 의존성, 설정 불필요
15
-
16
- ## 빠른 시작
17
-
18
- MCP 설정 파일(`.mcp.json` 또는 `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
- 또는 연결 문자열 사용:
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
- ### SSL을 사용하는 읽기 전용 모드
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "mysql": {
57
- "command": "npx",
58
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
59
- "env": {
60
- "MYSQL_HOST": "db.example.com",
61
- "MYSQL_USER": "readonly_user",
62
- "MYSQL_PASSWORD": "password",
63
- "MYSQL_DATABASE": "production",
64
- "MYSQL_SSL": "true",
65
- "MYSQL_QUERY_TIMEOUT": "10000"
66
- }
67
- }
68
- }
69
- }
70
- ```
71
-
72
- ## 도구
73
-
74
- | Tool | 설명 | 읽기 전용 모드 |
75
- |------|------|---------------|
76
- | `query` | SELECT, SHOW, DESCRIBE, EXPLAIN 실행 | 허용 |
77
- | `execute` | INSERT, UPDATE, DELETE, DDL 실행 | 차단 |
78
- | `list_databases` | 모든 데이터베이스 목록 조회 | 허용 |
79
- | `list_tables` | 데이터베이스의 테이블 목록 조회 | 허용 |
80
- | `describe_table` | 테이블 스키마 조회 | 허용 |
81
- | `describe_all_tables` | 모든 테이블 스키마를 한 번에 조회 | 허용 |
82
-
83
- ## 설정
84
-
85
- ### 환경 변수
86
-
87
- | 변수 | 필수 | 기본값 | 설명 |
88
- |------|------|--------|------|
89
- | `MYSQL_HOST` | Yes | — | MySQL 호스트 |
90
- | `MYSQL_USER` | Yes | — | MySQL 사용자 |
91
- | `MYSQL_PASSWORD` | Yes | — | MySQL 비밀번호 |
92
- | `MYSQL_PORT` | No | `3306` | MySQL 포트 |
93
- | `MYSQL_DATABASE` | No | — | 기본 데이터베이스 |
94
- | `MYSQL_READONLY` | No | `false` | 읽기 전용 모드 |
95
- | `MYSQL_MAX_ROWS` | No | `100` | SELECT 쿼리의 자동 LIMIT |
96
- | `MYSQL_QUERY_TIMEOUT` | No | `30000` | 쿼리 타임아웃 (밀리초, 0으로 비활성화) |
97
- | `MYSQL_SSL` | No | `false` | SSL 연결 활성화 |
98
-
99
- ### 연결 문자열
100
-
101
- ```
102
- mysql://user:password@host:port/database
103
- ```
104
-
105
- 첫 번째 CLI 인수로 전달됩니다. 환경 변수보다 우선합니다.
106
-
107
- ## 라이선스
108
-
109
- MIT
package/README.pt.md DELETED
@@ -1,109 +0,0 @@
1
- # @imrieul/mysql-mcp-server
2
-
3
- [English](./README.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md) | [中文](./README.zh.md) | [Español](./README.es.md) | [Français](./README.fr.md) | [Русский](./README.ru.md)
4
-
5
- Um servidor [MCP](https://modelcontextprotocol.io/) simples para MySQL.
6
-
7
- ## Recursos
8
-
9
- - **Otimizado para LLM** — formato compacto de colunas/linhas, LIMIT automático, dicas de erro com sugestões de próximas ações
10
- - **Schema em lote** — `describe_all_tables` retorna o schema completo do banco em uma única chamada
11
- - **Modo somente leitura** — verificação de prefixo no nível da aplicação + `SET SESSION TRANSACTION READ ONLY` no nível do banco
12
- - **Timeout de consulta** — timeout baseado em `Promise.race()` com limpeza garantida da conexão
13
- - **Suporte a SSL** — uma variável de ambiente para habilitar conexões criptografadas
14
- - **Minimalista** — 3 dependências, zero configuração necessária
15
-
16
- ## Início Rápido
17
-
18
- Adicione à sua configuração MCP (`.mcp.json` ou `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
- Ou com uma string de conexão:
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
- ### Modo somente leitura com SSL
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "mysql": {
57
- "command": "npx",
58
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
59
- "env": {
60
- "MYSQL_HOST": "db.example.com",
61
- "MYSQL_USER": "readonly_user",
62
- "MYSQL_PASSWORD": "password",
63
- "MYSQL_DATABASE": "production",
64
- "MYSQL_SSL": "true",
65
- "MYSQL_QUERY_TIMEOUT": "10000"
66
- }
67
- }
68
- }
69
- }
70
- ```
71
-
72
- ## Ferramentas
73
-
74
- | Ferramenta | Descrição | Modo somente leitura |
75
- |------|-------------|----------------|
76
- | `query` | Executar SELECT, SHOW, DESCRIBE, EXPLAIN | Permitido |
77
- | `execute` | Executar INSERT, UPDATE, DELETE, DDL | Bloqueado |
78
- | `list_databases` | Listar todos os bancos de dados | Permitido |
79
- | `list_tables` | Listar tabelas em um banco de dados | Permitido |
80
- | `describe_table` | Exibir schema da tabela | Permitido |
81
- | `describe_all_tables` | Exibir schemas de todas as tabelas de uma vez | Permitido |
82
-
83
- ## Configuração
84
-
85
- ### Variáveis de ambiente
86
-
87
- | Variável | Obrigatória | Padrão | Descrição |
88
- |----------|----------|---------|-------------|
89
- | `MYSQL_HOST` | Sim | — | Host do MySQL |
90
- | `MYSQL_USER` | Sim | — | Usuário do MySQL |
91
- | `MYSQL_PASSWORD` | Sim | — | Senha do MySQL |
92
- | `MYSQL_PORT` | Não | `3306` | Porta do MySQL |
93
- | `MYSQL_DATABASE` | Não | — | Banco de dados padrão |
94
- | `MYSQL_READONLY` | Não | `false` | Modo somente leitura |
95
- | `MYSQL_MAX_ROWS` | Não | `100` | LIMIT automático para consultas SELECT |
96
- | `MYSQL_QUERY_TIMEOUT` | Não | `30000` | Timeout de consulta em ms (0 para desabilitar) |
97
- | `MYSQL_SSL` | Não | `false` | Habilitar conexão SSL |
98
-
99
- ### String de conexão
100
-
101
- ```
102
- mysql://user:password@host:port/database
103
- ```
104
-
105
- Passada como primeiro argumento CLI. Tem prioridade sobre as variáveis de ambiente.
106
-
107
- ## Licença
108
-
109
- MIT
package/README.ru.md DELETED
@@ -1,109 +0,0 @@
1
- # @imrieul/mysql-mcp-server
2
-
3
- [English](./README.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md) | [中文](./README.zh.md) | [Español](./README.es.md) | [Português](./README.pt.md) | [Français](./README.fr.md)
4
-
5
- Простой MySQL-сервер [MCP](https://modelcontextprotocol.io/).
6
-
7
- ## Возможности
8
-
9
- - **LLM-friendly** — компактный формат столбцов/строк, автоматический LIMIT, подсказки об ошибках с предложениями следующих действий
10
- - **Массовая схема** — `describe_all_tables` возвращает полную схему БД за один вызов
11
- - **Режим только для чтения** — проверка префикса на уровне приложения + `SET SESSION TRANSACTION READ ONLY` на уровне БД
12
- - **Тайм-аут запросов** — тайм-аут на основе `Promise.race()` с гарантированной очисткой соединения
13
- - **Поддержка SSL** — одна переменная окружения для включения зашифрованных соединений
14
- - **Минималистичность** — 3 зависимости, нулевая конфигурация
15
-
16
- ## Быстрый старт
17
-
18
- Добавьте в конфигурацию MCP (`.mcp.json` или `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
- Или с использованием строки подключения:
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
- ### Режим только для чтения с SSL
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "mysql": {
57
- "command": "npx",
58
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
59
- "env": {
60
- "MYSQL_HOST": "db.example.com",
61
- "MYSQL_USER": "readonly_user",
62
- "MYSQL_PASSWORD": "password",
63
- "MYSQL_DATABASE": "production",
64
- "MYSQL_SSL": "true",
65
- "MYSQL_QUERY_TIMEOUT": "10000"
66
- }
67
- }
68
- }
69
- }
70
- ```
71
-
72
- ## Инструменты
73
-
74
- | Инструмент | Описание | Режим только для чтения |
75
- |------------|----------|-------------------------|
76
- | `query` | Выполнение SELECT, SHOW, DESCRIBE, EXPLAIN | Разрешено |
77
- | `execute` | Выполнение INSERT, UPDATE, DELETE, DDL | Заблокировано |
78
- | `list_databases` | Список всех баз данных | Разрешено |
79
- | `list_tables` | Список таблиц в базе данных | Разрешено |
80
- | `describe_table` | Отображение схемы таблицы | Разрешено |
81
- | `describe_all_tables` | Отображение всех схем таблиц одновременно | Разрешено |
82
-
83
- ## Конфигурация
84
-
85
- ### Переменные окружения
86
-
87
- | Переменная | Обязательная | По умолчанию | Описание |
88
- |------------|--------------|--------------|----------|
89
- | `MYSQL_HOST` | Да | — | Хост MySQL |
90
- | `MYSQL_USER` | Да | — | Пользователь MySQL |
91
- | `MYSQL_PASSWORD` | Да | — | Пароль MySQL |
92
- | `MYSQL_PORT` | Нет | `3306` | Порт MySQL |
93
- | `MYSQL_DATABASE` | Нет | — | База данных по умолчанию |
94
- | `MYSQL_READONLY` | Нет | `false` | Режим только для чтения |
95
- | `MYSQL_MAX_ROWS` | Нет | `100` | Автоматический LIMIT для SELECT-запросов |
96
- | `MYSQL_QUERY_TIMEOUT` | Нет | `30000` | Тайм-аут запроса в мс (0 для отключения) |
97
- | `MYSQL_SSL` | Нет | `false` | Включить SSL-соединение |
98
-
99
- ### Строка подключения
100
-
101
- ```
102
- mysql://user:password@host:port/database
103
- ```
104
-
105
- Передается как первый аргумент CLI. Имеет приоритет над переменными окружения.
106
-
107
- ## Лицензия
108
-
109
- MIT
package/README.zh.md DELETED
@@ -1,109 +0,0 @@
1
- # @imrieul/mysql-mcp-server
2
-
3
- [English](./README.md) | [한국어](./README.ko.md) | [日本語](./README.ja.md) | [Español](./README.es.md) | [Português](./README.pt.md) | [Français](./README.fr.md) | [Русский](./README.ru.md)
4
-
5
- 一个简单的 MySQL [MCP](https://modelcontextprotocol.io/) 服务器。
6
-
7
- ## 功能特性
8
-
9
- - **LLM 友好** — 紧凑的列/行格式,自动 LIMIT,提供错误提示和下一步操作建议
10
- - **批量模式架构** — `describe_all_tables` 一次调用返回整个数据库架构
11
- - **只读模式** — 应用层前缀检查 + 数据库层 `SET SESSION TRANSACTION READ ONLY`
12
- - **查询超时** — 基于 `Promise.race()` 的超时机制,确保连接清理
13
- - **SSL 支持** — 通过一个环境变量即可启用加密连接
14
- - **极简设计** — 仅 3 个依赖,无需配置即可使用
15
-
16
- ## 快速开始
17
-
18
- 将以下内容添加到您的 MCP 配置文件(`.mcp.json` 或 `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
- 或使用连接字符串:
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
- ### 启用 SSL 的只读模式
52
-
53
- ```json
54
- {
55
- "mcpServers": {
56
- "mysql": {
57
- "command": "npx",
58
- "args": ["-y", "@imrieul/mysql-mcp-server", "--readonly"],
59
- "env": {
60
- "MYSQL_HOST": "db.example.com",
61
- "MYSQL_USER": "readonly_user",
62
- "MYSQL_PASSWORD": "password",
63
- "MYSQL_DATABASE": "production",
64
- "MYSQL_SSL": "true",
65
- "MYSQL_QUERY_TIMEOUT": "10000"
66
- }
67
- }
68
- }
69
- }
70
- ```
71
-
72
- ## 工具
73
-
74
- | 工具 | 描述 | 只读模式 |
75
- |------|------|---------|
76
- | `query` | 执行 SELECT、SHOW、DESCRIBE、EXPLAIN | 允许 |
77
- | `execute` | 执行 INSERT、UPDATE、DELETE、DDL | 阻止 |
78
- | `list_databases` | 列出所有数据库 | 允许 |
79
- | `list_tables` | 列出数据库中的表 | 允许 |
80
- | `describe_table` | 显示表架构 | 允许 |
81
- | `describe_all_tables` | 一次性显示所有表架构 | 允许 |
82
-
83
- ## 配置
84
-
85
- ### 环境变量
86
-
87
- | 变量 | 必需 | 默认值 | 描述 |
88
- |------|------|--------|------|
89
- | `MYSQL_HOST` | 是 | — | MySQL 主机地址 |
90
- | `MYSQL_USER` | 是 | — | MySQL 用户名 |
91
- | `MYSQL_PASSWORD` | 是 | — | MySQL 密码 |
92
- | `MYSQL_PORT` | 否 | `3306` | MySQL 端口 |
93
- | `MYSQL_DATABASE` | 否 | — | 默认数据库 |
94
- | `MYSQL_READONLY` | 否 | `false` | 只读模式 |
95
- | `MYSQL_MAX_ROWS` | 否 | `100` | SELECT 查询自动 LIMIT 行数 |
96
- | `MYSQL_QUERY_TIMEOUT` | 否 | `30000` | 查询超时时间(毫秒,0 表示禁用) |
97
- | `MYSQL_SSL` | 否 | `false` | 启用 SSL 连接 |
98
-
99
- ### 连接字符串
100
-
101
- ```
102
- mysql://user:password@host:port/database
103
- ```
104
-
105
- 作为第一个 CLI 参数传递。优先级高于环境变量。
106
-
107
- ## 许可证
108
-
109
- MIT