mcp-database-server
About
Production-grade Model Context Protocol (MCP) server for unified SQL database access. Connect multiple databases through a single MCP server with schema discovery, relationship mapping, caching, and safety controls.
Details
- Author
- iprabhu
- Categories
- Database, Other
Jump to
Setup
Install mcp-database-server in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/iprabhu/mcp-database-server
Follow the installation instructions in the repository README, then restart your MCP client.
Production-grade Model Context Protocol (MCP) server for unified SQL database access. Connect multiple databases through a single MCP server with schema discovery, relationship mapping, caching, and safety controls.
Production-grade Model Context Protocol (MCP) server for unified SQL database access. Connect multiple databases through a single MCP server with schema discovery, relationship mapping, caching, and safety controls.
- npm:https://www.npmjs.com/package/@adevguide/mcp-database-server
- GitHub:https://github.com/iPraBhu/mcp-database-server
- Features
- Why this exists
- Installation
- Configuration
- MCP client integration
- Multi-database support: PostgreSQL, MySQL/MariaDB, SQLite, SQL Server, Oracle
- Automatic schema discovery: tables, columns, indexes, foreign keys, relationships
- Persistent schema caching: TTL + versioning, manual refresh, cache stats
- Relationship inference: foreign keys + heuristics
- Query intelligence: tracking, statistics, timeouts
- Join assistance: suggested join paths based on relationship graphs
- Safety controls: read-only mode, allow/deny write operations, secret redaction
- Query optimization: index recommendations, performance profiling, slow query detection
- Performance monitoring: detailed execution analytics, bottleneck identification
- Query rewriting: automated optimization suggestions with performance impact estimates
This project was originally vibe-coded to solve real issues I was facing when wiring LLM tools to multiple SQL databases (consistent connectivity, schema discovery, and safe query execution). It has since been hardened into a reusable MCP server with caching and security defaults.
┌─────────────────────────────────────────────────────────┐ │ MCP Client │ │ (Claude Desktop, IDEs, etc.) │ └────────────────┬────────────────────────────────────────┘ │ JSON-RPC over stdio ┌────────────────▼────────────────────────────────────────┐ │ MCP Database Server │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Schema Cache (TTL + Versioning) │ │ │ └──────────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Query Tracker (History + Statistics) │ │ │ └──────────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Security Layer (Read-only, Operation Controls) │ │ │ └──────────────────────────────────────────────────┘ │ └────┬─────────┬─────────┬──────────┬──────────┬─────────┘ │ │ │ │ │ ┌────▼───┐ ┌──▼────┐ ┌──▼─────┐ ┌──▼──────┐ ┌▼────────┐ │Postgres│ │ MySQL │ │ SQLite │ │ MSSQL │ │ Oracle │ └────────┘ └───────┘ └────────┘ └─────────┘ └─────────┘
npm install -g @adevguide/mcp-database-server
mcp-database-server --config /absolute/path/to/.mcp-database-server.config
npx -y @adevguide/mcp-database-server --config /absolute/path/to/.mcp-database-server.config
git clone https://github.com/iPraBhu/mcp-database-server.git cd mcp-database-server npm install npm run build node dist/index.js --config ./.mcp-database-server.config
Create a.mcp-database-server.configfile in your project root:
Note:The config file is automatically discovered inside the current project tree. If you don't specify--config, the tool searches upward from the current directory until it reaches the detected project root (for example a directory containingpackage.jsonor.git). It does not continue past the project root. If you usecredentialCommand, pass--configexplicitly.
{ "databases": [ { "id": "postgres-main", "type": "postgres", "secretRef": "DB_URL_POSTGRES", "readOnly": true, "pool": { "min": 2, "max": 10, "idleTimeoutMillis": 30000 }, "introspection": { "includeViews": true, "excludeSchemas": ["pg_catalog"] } }, { "id": "mariadb-reporting", "type": "mysql", "secretRef": "DB_URL_MARIADB", "readOnly": true, "pool": { "min": 1, "max": 5 } }, { "id": "sqlite-local", "type": "sqlite", "path": "./data/app.db" } ], "cache": { "directory": ".sql-mcp-cache", "ttlMinutes": 10 }, "security": { "allowWrite": false, "allowedWriteOperations": ["INSERT", "UPDATE"], "disableDangerousOperations": true, "redactSecrets": true }, "logging": { "level": "info", "pretty": false } }
Each database in thedatabasesarray represents a connection to a SQL database.
Required for postgres, mysql, mssql, oracle
Required for sqlite only
PostgreSQL: postgresql://username:password@host:5432/database MySQL: mysql://username:password@host:3306/database SQL Server: Server=host,1433;Database=dbname;User Id=user;Password=pass SQLite: (use path property instead) Oracle: username/password@host:1521/servicename
Thepoolobject controls connection pooling behavior. Improves performance by reusing database connections.
- Development:min: 1,max: 5
- Production (Low Traffic):min: 2,max: 10
- Production (High Traffic):min: 5,max: 20
Theintrospectionobject controls schema discovery behavior. Determines what database objects are analyzed.
- PostgreSQL/SQL Server:Support multiple schemas per database. UseincludeSchemas/excludeSchemas.
- MySQL/MariaDB:Schema = database. Use database name in connection string.
- SQLite:Single-file database, no schema concept.
Controls schema metadata caching to improve startup performance and reduce database load.
- On Startup:Loads schema from cache if available and not expired
- After TTL Expiry:Next query triggers automatic re-introspection
- Manual Refresh:Useclear_cachetool orintrospect_schemawithforceRefresh: true
- Cache Files:Stored as{database-id}.json(e.g.,postgres-main.json)
- Development:5minutes (schema changes frequently)
- Staging:30-60minutes
- Production (Static):1440minutes (24 hours)
- Production (Active):60-240minutes (1-4 hours)
Comprehensive security controls to protect your databases from unauthorized or dangerous operations.
- Database-levelreadOnly→ Blocks all writes for specific database
- GlobalallowWrite→ Master switch for all databases
- disableDangerousOperations→ Blocks DELETE/TRUNCATE/DROP specifically
- allowedWriteOperations→ Whitelist of permitted operations
// Read-only access (default - safest) { "allowWrite": false } // Allow INSERT and UPDATE only (no deletes) { "allowWrite": true, "allowedWriteOperations": ["INSERT", "UPDATE"], "disableDangerousOperations": true } // Full write access (development only - dangerous!) { "allowWrite": true, "disableDangerousOperations": false }
Controls log output verbosity and formatting.
- trace:Everything (extremely verbose - use for debugging only)
- debug:Detailed diagnostic information
- info:General informational messages (recommended for production)
- warn:Warning messages that don't prevent operation
- error:Error messages only
- Development:level: "debug",pretty: true
- Production:level: "info",pretty: false
- Troubleshooting:level: "trace",pretty: true
{ "databases": [ { "id": "postgres-production", "type": "postgres", "url": "${DATABASE_URL}", "readOnly": true, "pool": { "min": 5, "max": 20, "idleTimeoutMillis": 60000, "connectionTimeoutMillis": 5000 }, "introspection": { "includeViews": true, "includeRoutines": false, "excludeSchemas": ["pg_catalog", "information_schema"] }, "eagerConnect": true }, { "id": "mysql-analytics", "type": "mysql", "url": "${MYSQL_URL}", "readOnly": true, "pool": { "min": 2, "max": 10 }, "introspection": { "includeViews": true, "maxTables": 100 } }, { "id": "sqlite-local", "type": "sqlite", "path": "./data/app.db", "readOnly": true } ], "cache": { "directory": ".sql-mcp-cache", "ttlMinutes": 60 }, "security": { "allowWrite": false, "allowedWriteOperations": ["INSERT", "UPDATE"], "disableDangerousOperations": true, "redactSecrets": true }, "logging": { "level": "info", "pretty": false } }
Keep secrets out of the MCP client config and out of the server config values themselves.
{ "databases": [ { "id": "production-db", "type": "postgres", "secretRef": "DATABASE_URL" } ] }
The server resolvessecretReffrom the process environment first, and then from a.envfile next to.mcp-database-server.config.
DATABASE_URL=postgresql://user:password@localhost:5432/dbname DB_URL_MYSQL=mysql://user:password@localhost:3306/dbname DB_URL_MARIADB=mysql://report_user:password@mariadb.local:3306/reporting DB_URL_MSSQL=Server=host,1433;Database=db;User Id=sa;Password=pass
{ "databases": [ { "id": "analytics-db", "type": "mysql", "credentialCommand": "op read op://analytics/mysql/url" } ] }
The command must print only the connection string to stdout. For safety,credentialCommandis only allowed when the server is launched with an explicit--configpath. Auto-discovered configs cannot execute credential commands.
Still Supported: direct env interpolation
You can still write"url": "${DATABASE_URL}", butsecretRefis the cleaner option because it makes the secret source explicit.
- ✅ Store.envfile outside version control (add to.gitignore)
- ✅ Use different.envfiles for each environment (dev, staging, prod)
- ✅ Never commit credentials to git repositories
- ✅ Use secret management services (AWS Secrets Manager, HashiCorp Vault) in production
postgresql://user:pass@host:5432/db?sslmode=require&connect_timeout=10
mysql://user:pass@host:3306/db?charset=utf8mb4&timezone=Z
mysql://user:pass@host:3306/db?charset=utf8mb4
Server=host;Database=db;User Id=user;Password=pass;Encrypt=true;TrustServerCertificate=false
{ "mcpServers": { "database": { "command": "mcp-database-server", "args": ["--config", "/absolute/path/to/.mcp-database-server.config"] } } }
{ "mcpServers": { "database": { "command": "node", "args": [ "/absolute/path/to/mcp-database-server/dist/index.js", "--config", "/absolute/path/to/.mcp-database-server.config" ] } } }
# macOS/Linux cd /path/to/mcp-database-server pwd # prints: /Users/username/projects/mcp-database-server # Windows (PowerShell) cd C:\path\to\mcp-database-server $PWD.Path # prints: C:\Users\username\projects\mcp-database-server
This server provides 15 tools for comprehensive database interaction and optimization.
RequiresallowWrite: trueand respects security settings
Lists all configured databases with their connection status and cache information.
[ { "id": "postgres-main", "type": "postgres", "connected": true, "cached": true, "cacheAge": 45000, "version": "abc123" } ]
Discovers and caches complete database schema including tables, columns, indexes, foreign keys, and relationships.
{ "dbId": "postgres-main", "forceRefresh": false, "schemaFilter": { "includeSchemas": ["public"], "excludeSchemas": ["temp"], "includeViews": true, "maxTables": 100 } }
{ "dbId": "postgres-main", "version": "a1b2c3d4", "introspectedAt": "2026-01-26T10:00:00.000Z", "schemas": [ { "name": "public", "tableCount": 15, "viewCount": 3 } ], "totalTables": 15, "totalRelationships": 12 }
Retrieves detailed schema metadata from cache without querying the database.
{ "dbId": "postgres-main", "schema": "public", "table": "users" }
Response:Complete schema metadata including tables, columns, data types, indexes, foreign keys, and inferred relationships.
Executes SQL queries with automatic schema caching, relationship annotation, and comprehensive security controls.
{ "dbId": "postgres-main", "sql": "SELECT FROM users WHERE active = $1 ORDER BY id", "params": [true], "limit": 10, "offset": 0, "maxBytes": 32768, "includeMetadata": false, "trackQuery": false, "timeoutMs": 5000 }
{ "rows": [ {"id": 1, "name": "Alice", "email": "alice@example.com", "active": true}, {"id": 2, "name": "Bob", "email": "bob@example.com", "active": true} ], "columns": ["id", "name", "email", "active"], "rowCount": 2, "executionTimeMs": 15, "metadata": { "relationships": [...], "queryStats": { "totalQueries": 10, "avgExecutionTime": 20, "errorCount": 0 }, "pagination": { "limit": 10, "offset": 0, "hasMore": true, "nextOffset": 10 }, "responseSize": { "maxBytes": 32768, "rowsBytes": 1842, "rowsTrimmed": false, "omittedRowCount": 0 } } }
For the fastest MariaDB/MySQL read path, set"includeMetadata": falseand"trackQuery": falsewhen you only need result rows and do not need relationship annotations, query history, or performance analytics for that request.
- ✅ Write operations blocked by default (allowWrite: false)
- ✅ Dangerous operations (DELETE, TRUNCATE, DROP) disabled by default
- ✅ Specific operations can be whitelisted viaallowedWriteOperations
- ✅ Per-databasereadOnlymode
Retrieves database query execution plan without executing the query.
{ "dbId": "postgres-main", "sql": "SELECT FROM users JOIN orders ON users.id = orders.user_id WHERE users.active = $1", "params": [true] }
Response:**Database-native execution plan (format varies by database type).
Exports large read-only query results to a local file under.sql-mcp-cache/exports.
- MySQL/MariaDB uses adapter-level row streaming to avoid loading the full result set into memory.
- PostgreSQL and SQLite use paged export by rewriting top-levelLIMIT/OFFSETwindows.
- SQL Server export requires a future adapter-specific streaming path and will currently fail unless paging rewrite is supported.
{ "dbId": "mariadb-reporting", "sql": "SELECT id, email, created_at FROM users ORDER BY id", "format": "jsonl", "fileName": "users-export.jsonl", "timeoutMs": 10000 }
{ "dbId": "mariadb-reporting", "outputPath": "/absolute/path/to/.sql-mcp-cache/exports/users-export.jsonl", "format": "jsonl", "strategy": "stream", "rowsExported": 250000, "columns": ["id", "email", "created_at"], "fileSizeBytes": 18342011, "executionTimeMs": 8421 }
Analyzes relationship graph to recommend optimal join paths between multiple tables.
{ "dbId": "postgres-main", "tables": ["users", "orders", "products"] }
[ { "tables": ["users", "orders", "products"], "joins": [ { "fromTable": "users", "toTable": "orders", "relationship": { "type": "one-to-many", "confidence": 1.0 }, "joinCondition": "users.id = orders.user_id" }, { "fromTable": "orders", "toTable": "products", "relationship": { "type": "many-to-one", "confidence": 1.0 }, "joinCondition": "orders.product_id = products.id" } ], "sql": "FROM users JOIN orders ON users.id = orders.user_id JOIN products ON orders.product_id = products.id" } ]
Clears schema cache and query statistics for one or all databases.
{ "dbId": "postgres-main" }
Retrieves detailed cache statistics and health information.
{ "directory": ".sql-mcp-cache", "ttlMinutes": 10, "databases": [ { "dbId": "postgres-main", "cached": true, "version": "abc123", "age": 120000, "expired": false, "tableCount": 15, "sizeBytes": 45678 } ] }
Tests database connectivity and returns status information.
{ "databases": [ { "dbId": "postgres-main", "healthy": true, "connected": true, "version": "PostgreSQL 15.3", "responseTimeMs": 12 } ] }
Get comprehensive performance analytics across all queries for a database.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





