This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Model Context Protocol (MCP) server that provides MySQL database access to LLMs like Claude, with enhanced write operation support and Claude Code optimizations.
Key Technologies:
- TypeScript with ES Modules (NodeNext)
- MCP SDK (@modelcontextprotocol/sdk v1.15.1)
- mysql2 for database connectivity
- Vitest for testing
- Express for remote MCP mode (optional)
# Build TypeScript to dist/
pnpm build
# Watch mode (auto-rebuild on changes)
pnpm watch# Run built version
pnpm start
# Development mode with ts-node
pnpm dev
# Run directly with environment variables
pnpm exec# Setup test database (creates mcp_test DB and seeds data)
pnpm run setup:test:db
# Run all tests (includes pretest hook that runs setup:test:db)
pnpm test
# Run specific test suites
pnpm test:unit # Unit tests only
pnpm test:integration # Integration tests only
pnpm test:e2e # End-to-end tests only
pnpm test:socket # Socket connection tests
# Watch mode for development
pnpm test:watch
# Coverage report
pnpm test:coverageTest Environment Requirements:
- MySQL server running locally or remotely
- Test database user:
mcp_testwith passwordmcp_test_password - Test database:
mcp_test - Configuration via
.env.testfile
pnpm lintindex.ts- Main server file that exportscreateMcpServer()function- Supports both stdio and HTTP transport modes
- Handles MCP protocol setup and request routing
- Configures shutdown handlers for graceful cleanup
Configuration (src/config/index.ts)
- Loads environment variables via dotenv
- Exports connection config, permission flags, and mode detection
- Key exports:
mcpConfig- MySQL connection configurationisMultiDbMode- Boolean indicating multi-database modeALLOW_*_OPERATION- Global write permission flagsSCHEMA_*_PERMISSIONS- Schema-specific permission mapsMYSQL_DISABLE_READ_ONLY_TRANSACTIONS- Control transaction mode
Database Layer (src/db/index.ts)
- Connection pooling via
getPool()and lazy-loadedpoolPromise - Three query execution methods:
executeQuery<T>()- Basic query executionexecuteReadOnlyQuery<T>()- Enforces read-only transaction mode (unless disabled)executeWriteQuery<T>()- Handles INSERT/UPDATE/DELETE/DDL with transactions
- Permission checking integrated into query execution
- Schema extraction from queries for permission enforcement
Permissions (src/db/permissions.ts)
- Schema-specific permission checking functions:
isInsertAllowedForSchema(schema)isUpdateAllowedForSchema(schema)isDeleteAllowedForSchema(schema)isDDLAllowedForSchema(schema)
- Falls back to global permissions if no schema-specific rule exists
Utilities (src/db/utils.ts)
getQueryTypes()- Parses SQL to identify operation types (SELECT, INSERT, etc.)extractSchemaFromQuery()- Extracts database schema from qualified table names or USE statements
Resources (Database introspection):
ListResourcesRequest- Returns all tables across accessible schemasReadResourceRequest- Returns column metadata for specific tables- URIs:
mysql://tablesandmysql://tables/{tableName}
Tools (Query execution):
mysql_query- Single tool that executes SQL queries- Input:
{ sql: string } - Output: JSON result set with execution time
- Enforces permissions based on query type and target schema
When MYSQL_DB environment variable is empty or unset:
- Server operates in multi-DB mode
- Queries must use fully qualified table names (
database.table) orUSEstatements - Schema-specific permissions apply per database
- Write operations disabled by default unless
MULTI_DB_WRITE_MODE=true
Two-Level Hierarchy:
- Global flags:
ALLOW_INSERT_OPERATION,ALLOW_UPDATE_OPERATION,ALLOW_DELETE_OPERATION,ALLOW_DDL_OPERATION - Schema-specific overrides:
SCHEMA_*_PERMISSIONSenvironment variables
Format: SCHEMA_INSERT_PERMISSIONS=development:true,test:true,production:false
Transaction Safety:
- Read operations use
SET SESSION TRANSACTION READ ONLYby default - Can be disabled with
MYSQL_DISABLE_READ_ONLY_TRANSACTIONS=truefor DDL support - Write operations use explicit transactions with commit/rollback
When IS_REMOTE_MCP=true and REMOTE_SECRET_KEY is set:
- Starts Express HTTP server on
PORT(default 3000) - Accepts POST requests to
/mcpendpoint - Requires
Authorization: Bearer <REMOTE_SECRET_KEY>header - Uses StreamableHTTPServerTransport instead of stdio
.
├── index.ts # Main entry point
├── src/
│ ├── config/index.ts # Configuration and env loading
│ ├── db/
│ │ ├── index.ts # Database connection and query execution
│ │ ├── permissions.ts # Schema permission checks
│ │ └── utils.ts # SQL parsing utilities
│ ├── types/index.ts # TypeScript type definitions
│ └── utils/index.ts # General utilities (logging, etc.)
├── scripts/
│ └── setup-test-db.ts # Test database setup script
├── tests/
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests (MySQL required)
│ └── e2e/ # End-to-end server tests
├── evals.ts # MCP evaluation scripts
└── dist/ # Compiled JavaScript outputThe server supports two MySQL connection methods:
- TCP/IP: Set
MYSQL_HOSTandMYSQL_PORT - Unix Socket: Set
MYSQL_SOCKET_PATH(takes precedence over TCP/IP)
- Tests require a real MySQL instance
setup:test:dbscript must run before tests to create schema and seed data- Use
.env.testfor test-specific configuration - Integration tests cover multi-DB mode, schema permissions, and socket connections
- Uses
"type": "module"in package.json - All imports must include
.jsextension (TypeScript quirk for ES modules) tsconfig.jsonuses"module": "NodeNext"and"moduleResolution": "NodeNext"
safeExit()function prevents process.exit during tests- All database operations use try/catch with proper connection release
- Query errors include execution context and schema information
- Connection pooling with configurable limit (default 10)
- Query execution timing tracked via
performance.now() - Lazy pool initialization on first query
- Update SQL parser logic in
src/db/utils.ts(getQueryTypes) - Add permission checking in
src/db/index.ts(executeReadOnlyQuery) - Handle result formatting in
executeWriteQueryif needed - Add integration tests in
tests/integration/
- Add to
.envexample in README - Parse in
src/config/index.ts - Export for use in other modules
- Document in README's Environment Variables section
- Update permission functions in
src/db/permissions.ts - Modify schema extraction if needed in
src/db/utils.ts - Test with schema-specific permission scenarios
- Update permission checking in
executeReadOnlyQuery