UNPKG

@makeappeasy/query-protocol-server

Version:

A secure query protocol server for database operations with read-only access control

386 lines (308 loc) 11.3 kB
# Read-Only MySQL MCP Server A secure, read-only Model Context Protocol server for MySQL databases. This server enables AI assistants to safely explore and analyze MySQL databases without any risk of data modification. ## 🔒 Security-First Design This server implements **database-level read-only protection** using MySQL's native transaction capabilities, following the same pattern as the official PostgreSQL MCP server from Anthropic. ### How Read-Only Protection Works ```typescript // Every query is executed within a read-only transaction await connection.query('SET TRANSACTION READ ONLY'); await connection.query('START TRANSACTION'); const result = await connection.query(userSQL); // Any SQL allowed await connection.query('ROLLBACK'); // Always rollback ``` **Why this approach is bulletproof:** - 🛡️ **MySQL enforces the restriction** - impossible to bypass at application level - 🔓 **Full SQL flexibility** - SELECT, SHOW, DESCRIBE, EXPLAIN all work perfectly - 🚫 **Zero write risk** - INSERT, UPDATE, DELETE automatically rejected by database - 🔄 **Automatic cleanup** - Each query is isolated in its own transaction ## 🚀 Installation ```bash # Clone and install git clone <your-repo> cd mysql-mcp npm install npm run build ``` ### Quick Setup for Claude Code Users **🚀 Super Quick Setup (NPX - Recommended):** ```bash claude mcp add mysql-query-server \ -e MYSQL_HOST=your_host \ -e MYSQL_PORT=3306 \ -e MYSQL_USER=your_user \ -e MYSQL_PASSWORD=your_password \ -e MYSQL_DATABASE=your_database \ -- npx @makeappeasy/query-protocol-server@1.0.5 ``` **Example with real values:** ```bash claude mcp add mysql-query-server \ -e MYSQL_HOST=34.93.229.229 \ -e MYSQL_PORT=3306 \ -e MYSQL_USER=root \ -e MYSQL_PASSWORD=Letitgo@98 \ -e MYSQL_DATABASE=information_schema \ -- npx @makeappeasy/query-protocol-server@1.0.5 ``` **📦 Local Development Setup:** 1. **Clone and build** (one-time setup): ```bash git clone <your-repo> cd mysql-mcp npm install && npm run build ``` 2. **Add to Claude Code** (replace with your details): ```bash claude mcp add mysql-query-server \ -e MYSQL_HOST=your_host \ -e MYSQL_PORT=3306 \ -e MYSQL_USER=your_user \ -e MYSQL_PASSWORD=your_password \ -e MYSQL_DATABASE=your_database \ -- node /full/path/to/mysql-mcp/build/index.js ``` **✅ Ready to use** - Your AI assistant can now safely explore your database! ## ⚙️ Configuration ### Option 1: Claude Code CLI with NPX (Recommended) The easiest way to add this server to Claude Code using the published npm package: ```bash claude mcp add query-protocol-server npx @makeappeasy/query-protocol-server --env MYSQL_HOST=localhost --env MYSQL_PORT=3306 --env MYSQL_USER=root --env MYSQL_PASSWORD=your_password --env MYSQL_DATABASE=your_database ``` **Example with sample values:** ```bash claude mcp add query-protocol-server npx @makeappeasy/query-protocol-server --env MYSQL_HOST=192.168.1.100 --env MYSQL_PORT=3306 --env MYSQL_USER=dbuser --env MYSQL_PASSWORD=mypassword123 --env MYSQL_DATABASE=analytics_db ``` **Using MySQL URL format:** ```bash claude mcp add query-protocol-server npx @makeappeasy/query-protocol-server mysql://dbuser:mypassword123@192.168.1.100:3306/analytics_db ``` ### Option 2: Claude Code CLI with Local Build If you prefer to use your local build: ```bash claude mcp add query-protocol-server node /path/to/mysql-mcp/build/index.js --env MYSQL_HOST=localhost --env MYSQL_PORT=3306 --env MYSQL_USER=root --env MYSQL_PASSWORD=your_password --env MYSQL_DATABASE=your_database ``` ### Option 3: Manual Configuration - NPX with JSON ```json { "mcpServers": { "query-protocol-server": { "command": "npx", "args": ["@makeappeasy/query-protocol-server", "mysql://user:password@localhost:3306/database"] } } } ``` ### Option 4: Manual Configuration - Local Build ```json { "mcpServers": { "mysql-readonly": { "command": "node", "args": ["/path/to/mysql-mcp/build/index.js", "mysql://user:password@localhost:3306/database"] } } } ``` ### Option 5: Manual Configuration - Environment Variables ```json { "mcpServers": { "query-protocol-server": { "command": "npx", "args": ["@makeappeasy/query-protocol-server"], "env": { "MYSQL_HOST": "localhost", "MYSQL_USER": "your_user", "MYSQL_PASSWORD": "your_password", "MYSQL_DATABASE": "your_database", "MYSQL_PORT": "3306" } } } } ``` ### Option 6: Local Build with Environment Variables ```json { "mcpServers": { "mysql-readonly": { "command": "node", "args": ["/path/to/mysql-mcp/build/index.js"], "env": { "MYSQL_HOST": "localhost", "MYSQL_USER": "your_user", "MYSQL_PASSWORD": "your_password", "MYSQL_DATABASE": "your_database", "MYSQL_PORT": "3306" } } } } ``` ### Option 7: Direct Execution ```bash # Using NPX with MySQL URL npx @makeappeasy/query-protocol-server mysql://user:password@localhost:3306/database # Using NPX with environment variables MYSQL_HOST=localhost MYSQL_USER=root MYSQL_PASSWORD=secret MYSQL_DATABASE=mydb npx @makeappeasy/query-protocol-server # Using local build node build/index.js mysql://user:password@localhost:3306/database ``` ## 🛠️ Available Tools ### 1. connect_db Establish or change database connection during runtime. ```javascript { "tool": "connect_db", "arguments": { "host": "localhost", "user": "readonly_user", "password": "secure_password", "database": "analytics_db", "port": 3306 } } ``` ### 2. query Execute any read-only SQL query with full flexibility. ```javascript { "tool": "query", "arguments": { "sql": "SELECT users.name, COUNT(orders.id) as order_count FROM users LEFT JOIN orders ON users.id = orders.user_id WHERE users.created_at >= ? GROUP BY users.id ORDER BY order_count DESC LIMIT 10", "params": ["2024-01-01"] } } ``` **Supported query types:** - `SELECT` - Data retrieval with joins, aggregations, subqueries - `SHOW` - Database/table/column information - `DESCRIBE` / `DESC` - Table structure - `EXPLAIN` - Query execution plans - `ANALYZE TABLE` - Table statistics - `INSERT`, `UPDATE`, `DELETE` - Blocked by database - `DROP`, `CREATE`, `ALTER` - Blocked by database - `GRANT`, `REVOKE`, `SET` - Blocked by database ### 3. list_tables Get all tables in the current database. ```javascript { "tool": "list_tables", "arguments": {} } ``` ### 4. describe_table Get detailed table structure and column information. ```javascript { "tool": "describe_table", "arguments": { "table": "users" } } ``` ## 💡 Perfect for Data Analysis This server is specifically designed for AI-powered data analysis scenarios: ### Complex Analytics Queries ```sql -- Customer cohort analysis SELECT DATE_FORMAT(signup_date, '%Y-%m') as cohort_month, COUNT(DISTINCT user_id) as cohort_size, COUNT(DISTINCT CASE WHEN first_purchase_date IS NOT NULL THEN user_id END) as converted_users, ROUND(COUNT(DISTINCT CASE WHEN first_purchase_date IS NOT NULL THEN user_id END) * 100.0 / COUNT(DISTINCT user_id), 2) as conversion_rate FROM user_analytics WHERE signup_date >= DATE_SUB(NOW(), INTERVAL 12 MONTH) GROUP BY DATE_FORMAT(signup_date, '%Y-%m') ORDER BY cohort_month; ``` ### Business Intelligence Queries ```sql -- Revenue analysis with trending SELECT product_category, SUM(CASE WHEN order_date >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN revenue END) as last_30_days, SUM(CASE WHEN order_date >= DATE_SUB(NOW(), INTERVAL 60 DAY) AND order_date < DATE_SUB(NOW(), INTERVAL 30 DAY) THEN revenue END) as prev_30_days, ROUND((SUM(CASE WHEN order_date >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN revenue END) - SUM(CASE WHEN order_date >= DATE_SUB(NOW(), INTERVAL 60 DAY) AND order_date < DATE_SUB(NOW(), INTERVAL 30 DAY) THEN revenue END)) * 100.0 / NULLIF(SUM(CASE WHEN order_date >= DATE_SUB(NOW(), INTERVAL 60 DAY) AND order_date < DATE_SUB(NOW(), INTERVAL 30 DAY) THEN revenue END), 0), 2) as growth_rate FROM order_analytics GROUP BY product_category HAVING last_30_days > 0 ORDER BY growth_rate DESC; ``` ## 🔐 Security Features ### Database-Level Protection - **MySQL Transaction Read-Only**: Uses `SET TRANSACTION READ ONLY` for bulletproof security - **Automatic Rollback**: Every query is rolled back, ensuring no persistent changes - **Isolation**: Each query runs in its own isolated transaction ### Application-Level Security - **Prepared Statements**: All parameterized queries use MySQL prepared statements - **Connection Management**: Proper connection lifecycle with automatic cleanup - **Error Handling**: Sanitized error messages prevent information disclosure ### Zero-Risk Architecture - **No Write Tools**: Complete removal of any write-capable functionality - **Database Enforcement**: Security is enforced by MySQL itself, not application logic - **Impossible Bypass**: No way to circumvent read-only restrictions ## 🎯 Use Cases ### Ideal For - **Data exploration** by AI assistants - **Business intelligence** and analytics - **Database schema** investigation - **Performance analysis** with EXPLAIN queries - **Production database** access for read-only operations - **Multi-user environments** with sensitive data ### Not Suitable For - Data modification or ETL operations - Database administration tasks - Schema changes or migrations - User management or permissions ## 🏗️ Architecture Built on modern, professional foundations: - **TypeScript** - Full type safety and excellent developer experience - **ESModules** - Modern JavaScript module system - **MCP SDK** - Official Model Context Protocol implementation - **MySQL2** - Mature, performant MySQL driver with prepared statement support - **Professional Error Handling** - Comprehensive error management and reporting ## 🚀 Development ```bash # Development mode with auto-rebuild npm run watch # Build for production npm run build # Start the server npm start ``` ## 🔧 Troubleshooting ### Claude Code Setup Issues **Path Problems:** ```bash # Get absolute path first pwd # Output: /Users/username/mysql-mcp # Then use full path in claude command claude mcp add mysql-readonly-server node /Users/username/mysql-mcp/build/index.js --env MYSQL_HOST=... ``` **Connection Testing:** ```bash # Test connection with NPX npx @makeappeasy/query-protocol-server mysql://user:pass@host:port/database # Should show: "MySQL MCP server running on stdio" # Test connection with local build node build/index.js mysql://user:pass@host:port/database ``` **Common Claude Code Commands:** ```bash # List configured servers claude mcp list # Remove server if needed claude mcp remove query-protocol-server # Re-add with NPX (recommended) claude mcp add query-protocol-server npx @makeappeasy/query-protocol-server --env MYSQL_HOST=... # Re-add with local build claude mcp add query-protocol-server node /path/to/build/index.js --env MYSQL_HOST=... ``` ## 📄 License MIT - See LICENSE file for details. --- **🔒 Security First 📊 Analytics Ready 🛠️ Production Tested**