MySQL MCP

by codechap

Not rated
GitHub

About

MCP server for MySQL/MariaDB — schema inspection, queries, and data manipulation for AI assistants

Details

Author
codechap
Categories
Database, Other

Setup

Install MySQL MCP in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/codechap/mcp-server-mysql

Follow the installation instructions in the repository README, then restart your MCP client.

A high-quality Model Context Protocol (MCP) server implementation for MySQL databases. This server enables AI assistants like Claude to interact with MySQL databases through a standardized protocol.

Version: 0.2.0 |Protocol: MCP 2025-03-26 |Rust: 1.70+ |Status: Production Ready

- Features
-
Installation
-
Quick Start (5 Minutes)
-
Usage
-
Available Tools
-
Database Context Feature
-
Security Considerations
-
Architecture
-
Troubleshooting
-
Development
-
Deployment Guide
-
Contributing
-
License
-
Support

- Schema Inspection: Retrieve table schemas and structure information
- Query Execution: Execute SQL queries (read-only by default for safety)
- Data Manipulation: Insert, update, and delete operations
- Database Context: Specify which database to use per query
- Safety Controls: Configurable query restrictions to prevent dangerous operations
- Connection Management: Robust connection handling with retry logic and pooling
- Error Handling: Comprehensive error reporting with detailed messages
- JSON-RPC 2.0 Protocol: Standardized communication via stdio

- Rust 1.70+
- MySQL 5.7+ or MariaDB 10.2+
- Access to a MySQL database

git clone <repository-url> cd mcp-server-mysql cargo build --release

The compiled binary will be available attarget/release/mcp-server-mysql.

# Extract the package tar -xzf mcp-server-mysql-v0.2.0-linux-x86_64.tar.gz # Move binary to system path (optional) sudo cp mcp-server-mysql /usr/local/bin/ # Verify installation mcp-server-mysql --version

The binary will be attarget/release/mcp-server-mysql

./target/release/mcp-server-mysql \ --host localhost \ --username root \ --password yourpassword \ --database testdb

You should see: "MCP MySQL Server started and ready to accept connections"

Edit your Claude Desktop configuration file:

- macOS:~/Library/Application Support/Claude/claude_desktop_config.json
- Windows:%APPDATA%\Claude\claude_desktop_config.json

{ "mcpServers": { "mysql": { "command": "/absolute/path/to/mcp-server-mysql", "args": [ "--host", "localhost", "--port", "3306", "--username", "your_username", "--password", "your_password", "--database", "your_database" ] } } }

Security Note: For production use, consider using environment variables or a secure secrets management solution instead of hardcoding passwords in the configuration file.

Close and reopen Claude Desktop completely. You should see a small hammer icon indicating the MCP server is connected.

- "Can you show me the schema for the users table in my MySQL database?"
- "Query the database and show me the first 10 rows from the products table"
- "What tables are in my database?"

mcp-server-mysql \ --host localhost \ --port 3306 \ --username your_username \ --password your_password \ --database your_database \ --allow-dangerous-queries false

Add this configuration to your Claude Desktop config file:

macOS:~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.json

{ "mcpServers": { "mysql": { "command": "/path/to/mcp-server-mysql", "args": [ "--host", "localhost", "--port", "3306", "--username", "your_username", "--password", "your_password", "--database", "your_database" ] } } }

Retrieve database schema information for tables.

- table_name(string): Name of the table to inspect, or"all-tables"to get all table schemas

{ "table_name": "users" }

- Column information (name, type, nullable, defaults, keys)
- Index information
- Table constraints

- query(string): SQL query to execute
- database(string, optional): Database name to use for this specific query

{ "query": "SELECT  FROM users WHERE active = 1 LIMIT 10", "database": "my_database" }

- By default, only SELECT queries are allowed
- Use--allow-dangerous-queriesflag to enable INSERT/UPDATE/DELETE
- Dangerous keywords are blocked unless explicitly enabled

- table_name(string): Name of the table
- data(object): Key-value pairs of column names and values

{ "table_name": "users", "data": { "username": "john_doe", "email": "john@example.com", "active": true } }

Update data in a specified table based on conditions.

- table_name(string): Name of the table
- data(object): Key-value pairs of columns to update
- conditions(object): Key-value pairs for WHERE clause

{ "table_name": "users", "data": { "email": "newemail@example.com", "updated_at": "2024-01-15 10:30:00" }, "conditions": { "id": 123 } }

Delete data from a specified table based on conditions.

- table_name(string): Name of the table
- conditions(object): Key-value pairs for WHERE clause

{ "table_name": "users", "conditions": { "id": 123 } }

Warning:Always specify conditions to avoid deleting all rows!

Previously, database context was not maintained between queries:

-- Query 1 USE dev_database; -- Succeeds -- Query 2 (new connection from pool) SELECT  FROM my_table; -- ❌ Fails: context was lost

Use the optionaldatabaseparameter on each query:

{ "query": "SELECT  FROM my_table", "database": "dev_database" }

- Explicit and Clear: Know exactly which database each query uses
- No Hidden State: Each query is independent
- Backward Compatible: Existing queries without parameter still work
- No Race Conditions: Each query gets its own connection
- Simple to Use: Just add"database": "name"to query arguments

{ "query": "SELECT  FROM crm_sites LIMIT 10", "database": "dev_smartConnect_za" }

Query Without Database Parameter (Uses Default)

{ "query": "SELECT  FROM users WHERE active = 1" }

Uses the database specified in--databasestartup argument.

// Query database 1 { "query": "SELECT COUNT() FROM customers", "database": "production_db" } // Query database 2 { "query": "SELECT COUNT() FROM test_data", "database": "test_db" }

Before (Required fully qualified names):

SELECT  FROM dev_smartConnect_za.crm_sites JOIN dev_smartConnect_za.crm_orgs ON ... WHERE dev_smartConnect_za.crm_sites.active = 1;
{ "query": "SELECT  FROM crm_sites JOIN crm_orgs ON ... WHERE active = 1", "database": "dev_smartConnect_za" }

Set default database and omit the parameter:

# Startup --database my_project_db # Query (no database parameter needed) { "query": "SELECT  FROM users" }
// Customer database { "query": "...", "database": "customers_db" } // Orders database { "query": "...", "database": "orders_db" } // Analytics database { "query": "...", "database": "analytics_db" }

Error Code -32005: Connection Acquisition Failed

Cause: Connection pool exhausted Solution: Retry after a moment

Error Code -32006: Database Context Switch Failed

Cause: Database doesn't exist or user lacks permissions Solution: Verify database exists and user has access

- Specify database explicitly for production queries
- Use descriptive database names in your queries
- Test withSELECT DATABASE()to verify context
- Group queries by database for clarity

- Mix qualified and unqualified names in the same query
- Assume persistence - specify database for each query
- Use special characters in database names if possible
- Forget to verify user permissions for all databases

By default, the server operates in read-only mode, allowing only SELECT queries. This prevents accidental data modification or deletion.

Enable write operations with--allow-dangerous-queries:

mcp-server-mysql --username user --password pass --database mydb --allow-dangerous-queries true

- INSERT statements
- UPDATE statements
- DELETE statements
- Other potentially destructive operations

- Table names are validated to contain only alphanumeric characters and underscores
- All data values are parameterized using prepared statements
- Database names are escaped by replacing backticks with double backticks
- No raw SQL concatenation is performed

- Supports standard MySQL SSL/TLS connections
- Connection strings can be configured securely
- Passwords can be provided via environment variables
- Consider using dedicated database users with limited permissions

CREATE USER 'mcp_user'@'localhost' IDENTIFIED BY 'secure_password'; GRANT SELECT ON your_database.* TO 'mcp_user'@'localhost'; FLUSH PRIVILEGES;
--allow-dangerous-queries true # Use with caution!

Use environment variables(future enhancement): Consider wrapping the binary in a shell script that reads from env vars.

┌─────────────────────────────────────────────────────┐ │ MCP Client (e.g., Claude) │ │ Sends: {query, database} │ └────────────────────────┬────────────────────────────┘ │ JSON-RPC 2.0 (stdio) ▼ ┌─────────────────────────────────────────────────────┐ │ MCP MySQL Server (Rust) │ │ │ │ execute_query(query, database, pool) │ │ ├─ If database param: │ │ │ ├─ Acquire connection from pool │ │ │ ├─ Execute: USE database │ │ │ └─ Execute: [user's query] │ │ └─ Else: │ │ └─ Execute query on pool (default database) │ └────────────────────────┬────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ MySQL Connection Pool (5 connections) │ └────────────────────────┬────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ MySQL/MariaDB Server │ └─────────────────────────────────────────────────────┘
Client MCP Server Connection Pool MySQL Server │ │ │ │ │ query + │ │ │ │ database │ │ │ ├────────────────>│ │ │ │ │ │ │ │ │ acquire() │ │ │ ├───────────────────>│ │ │ │ <connection> │ │ │ │<───────────────────┤ │ │ │ │ │ │ │ USE database │ │ │ ├────────────────────┼─────────────────>│ │ │ OK │ │ │ │<────────────────────┼──────────────────┤ │ │ │ │ │ │ SELECT query │ │ │ ├────────────────────┼─────────────────>│ │ │ Results │ │ │ │<────────────────────┼──────────────────┤ │ │ │ │ │ │ release() │ │ │ ├───────────────────>│ │ │ Results │ │ │ │<────────────────┤ │ │
Pool (5 connections) ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ C1 │ │ C2 │ │ C3 │ │ C4 │ │ C5 │ └────┘ └────┘ └────┘ └────┘ └────┘ Key Properties: • Each query gets its own connection instance • Database context is set per connection, per query • No state persists between queries • Fully thread-safe and concurrent

- Protocol Version: MCP 2025-03-26
- Transport: stdio (JSON-RPC 2.0)
- Connection Pooling: Max 5 connections
- Retry Logic: Automatic reconnection on transient failures
- Performance Overhead: ~50-200 microseconds per query with database parameter

- Ensure the username and password are correct
- Confirm the user has access to the specified database

- Verify the host and port are correct
- Ensure no firewall is blocking the connection

- The server logs to stderr
- Check for detailed error messages

- MySQL server may not be running
- Incorrect host/port configuration
- Network connectivity issues

"Only SELECT queries are allowed"

- You're trying to run a write query in read-only mode
- Add--allow-dangerous-queries trueif write access is needed

- The specified database doesn't exist
- The user doesn't have access to the database
- CheckSHOW DATABASES;to see available databases

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.