The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Db MCP Server listing page.
The DB MCP Server provides a standardized way for AI models to interact with multiple databases simultaneously. Built on the FreePeak/cortex framework, it enables AI assistants to execute SQL queries, manage transactions, explore schemas, and analyze performance across different database systems through a unified interface.
Unlike traditional database connectors, DB MCP Server can connect to and interact with multiple databases concurrently:
For each connected database, the server automatically generates specialized tools:
The server follows Clean Architecture principles with these layers:
--lazy-loading flag)read_only enforcement (blocks writes through both query_* and execute_* tools), max_rows result truncation with explicit notices, and per-query timeoutsProtect agent sessions against runaway queries and accidental writes:
| Setting | Scope | Effect |
|---|---|---|
"read_only": true | per database | Blocks write statements (INSERT, UPDATE, DELETE, DDL, data-modifying CTEs, stacked writes) through both query and execute tools, and enforces rejection at the database engine itself on PostgreSQL/TimescaleDB (default_transaction_read_only=on) and MySQL (transaction_read_only=1); SQLite opens mode=ro. Classification strips comments and string literals and defaults to deny for unrecognized statements. |
"max_rows": 1000 | per database | Truncates result sets at N rows and appends an explicit [Truncated] notice so the model knows to refine its query instead of losing context. 0 (default) means unlimited. |
"masking_rules": [...] | per database | Masks values of result columns whose name matches a rule's regex before they leave the server — applies to every query shape including SELECT *. Strategies: "fixed_string" (replace with value), "null", and "partial" (keep_last trailing characters visible; shorter values fully masked). First matching rule wins; invalid patterns or unknown strategies abort config load (fail closed); masked-cell counts are reported in the result footer. Renaming a column with an alias bypasses name matching by design. See docs/design/column-masking-scoping.md. |
"query_timeout": 30 | per database | Cancels statements that exceed the timeout in seconds; enforced at the repository layer for every tool (queries, statements, transactions, explain, schema inspection). Unset defaults to 30s; -1 disables. Env-only deployments can set QUERY_TIMEOUT_SECONDS to fill connections without an explicit value (JSON keeps precedence). |
| DB_MCP_AUDIT_LOG=/path/audit.jsonl | process | Appends one JSONL record per executed statement — timestamp, op (query/execute/tx_*), database, statement (capped at 10k chars), duration, error. Includes rejected attempts against read-only databases. Best-effort writes never fail a query; file is created with 0600. |
Defense in depth: read-only is enforced in three layers — application classifier, engine session defaults, and (recommended) least-privilege database users. Oracle currently relies on the classifier plus user privileges.
| Database | Status | Features |
|---|---|---|
| MySQL | ✅ Full Support | Queries, Transactions, Schema Analysis, Performance Insights |
| PostgreSQL | ✅ Full Support (v9.6-17) | Queries, Transactions, Schema Analysis, Performance Insights |
| SQLite | ✅ Full Support | File-based & In-memory databases, SQLCipher encryption support |
| Oracle | ✅ Full Support (10g-23c) | Queries, Transactions, Schema Analysis, RAC, Cloud Wallet, TNS |
| TimescaleDB | ✅ Full Support | Time-Series Queries, Hypertable Discovery (write policies via SQL) |
The DB MCP Server can be deployed in multiple ways to suit different environments and integration needs:
Note: Mount to
/app/my-config.jsonas the container has a default file at/app/config.json.
The SSE and streamable-HTTP transports accept an Authorization: Bearer <key>
header. Set DB_MCP_API_KEY (or pass -api-key) when launching the Docker
container; clients must then send the matching bearer token on every request:
When no API key is configured the transport remains open (single-user /
development use). The middleware lives in internal/delivery/mcp.APIKeyAuth
and is exported so you can compose it with your own reverse proxy if you
front the container with nginx, Caddy, or Traefik.
For Cursor IDE integration, add to .cursor/mcp.json:
Client connection endpoint: http://localhost:9092/sse
Create a config.json file with your database connections:
Available Flags:
-t, -transport: Transport mode (stdio or sse)-c, -config: Path to database configuration file-p, -port: Server port for SSE mode (default: 9092)-h, -host: Server host for SSE mode (default: localhost)-log-level: Log level (debug, info, warn, error)-log-dir: Directory for log files (default: ./logs in current directory)-db-config: Inline JSON database configurationValues in a .env file are loaded first; real environment variables take precedence. A JSON config file (CONFIG_PATH/DB_CONFIG_FILE) overrides per-database env vars.
| Variable | Default | Purpose |
|---|---|---|
CONFIG_PATH / DB_CONFIG_FILE | config.json | Path to the multi-database JSON config |
DB_CONFIG | — | Inline JSON database configuration (alternative to a file) |
TRANSPORT_MODE | sse | Transport mode when -t is not passed |
SERVER_PORT | 9090 | HTTP port for SSE mode |
LOG_LEVEL | info | Log verbosity (debug, info, warn, error) |
DISABLE_LOGGING | false | true/1 silences logging entirely |
DB_TYPE, DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME | engine defaults | Single-database fallback when no JSON config exists |
QUERY_TIMEOUT_SECONDS | unset | Fills connections that don't set their own query_timeout; negative disables the cap. JSON configs keep precedence. |
When using SQLite databases, you can leverage these additional configuration options:
| Parameter | Type | Default | Description |
|---|---|---|---|
database_path | string | Required | Path to SQLite database file or :memory: for in-memory |
encryption_key | string | - | Key for SQLCipher encrypted databases |
read_only | boolean | false | Open database in read-only mode |
max_rows | integer | unlimited | Maximum rows returned per query; larger results are truncated with an explicit notice. Works on all database types |
cache_size | integer | 2000 | SQLite cache size in pages |
journal_mode | string | "WAL" | Journal mode: DELETE, TRUNCATE, PERSIST, WAL, OFF |
use_modernc_driver | boolean | true | Use modernc.org/sqlite (CGO-free) or mattn/go-sqlite3 |
When using Oracle databases, you can leverage these additional configuration options:
| Parameter | Type | Default | Description |
|---|---|---|---|
host | string | Required | Oracle database host |
port | integer | 1521 | Oracle listener port |
service_name | string | - | Service name (recommended for RAC) |
sid | string | - | System identifier (legacy, use service_name instead) |
user | string | Required | Database username |
password | string | Required | Database password |
wallet_location | string | - | Path to Oracle Cloud wallet directory |
tns_admin | string | - | Path to directory containing tnsnames.ora |
tns_entry | string | - | Named entry from tnsnames.ora |
edition | string | - | Edition-Based Redefinition edition name |
pooling | boolean | false | Enable driver-level connection pooling |
standby_sessions | boolean | false | Allow queries on standby databases |
nls_lang | string | AMERICAN_AMERICA.AL32UTF8 | Character set configuration |
When multiple connection methods are configured, the following priority is used:
tns_entry and tns_admin are configured)wallet_location is configured) - for Oracle CloudFor each connected database, DB MCP Server automatically generates these specialized tools:
| Tool Name | Description |
|---|---|
query_<db_id> | Execute SELECT queries and get results as a tabular dataset |
execute_<db_id> | Run data manipulation statements (INSERT, UPDATE, DELETE) |
transaction_<db_id> | Begin, commit, and rollback transactions |
| Tool Name | Description |
|---|---|
schema_<db_id> | Get information about tables, columns, indexes, and foreign keys |
generate_schema_<db_id> | Generate SQL or code from database schema |
| Tool Name | Description |
|---|---|
performance_<db_id> | Analyze query performance via actions: stats / slow_queries (in-process tracker), engine_slow_queries (pg_stat_statements / MySQL digest tables / Oracle v$sqlarea), suggest (static SQL lint), suggest_indexes (heuristic CREATE INDEX advice for one statement, equality-first composites, verify with EXPLAIN), validate_suggestions (PostgreSQL: installs the same suggestions as cost-free hypothetical indexes via the hypopg extension and reports whether the planner actually picks each one — ground-truth validation instead of manual EXPLAIN), workload_suggestions (same analysis across the top-N expensive workload statements, weighted by executions), index_health (duplicate/redundant/unused/invalid indexes and table bloat findings from catalogs; usage evidence where engine statistics exist), db_health (everything index_health covers plus connection-pressure utilization vs max_connections), reset |
explain_<db_id> | Show the execution plan for a SQL statement without running it; analyze: true executes with timing/buffer stats (PostgreSQL/MySQL). Writes stay blocked on read-only databases |
describe_<db_id> | Inspect one table's columns, indexes, and row estimate via engine catalog queries |
health_<db_id> | Report connectivity, ping latency, connection-pool state, and engine stats (PostgreSQL buffer-cache hit ratio, MySQL InnoDB buffer efficiency) |
For PostgreSQL databases with the timescaledb extension installed, these additional
specialized tools are registered automatically at startup (registration is config-driven,
so it also works under --lazy-loading; each handler verifies the extension at call time
and returns an actionable error when it is absent):
| Tool Name | Description |
|---|---|
timescaledb_timeseries_query_<db_id> | Execute optimized time-series queries with time bucketing (time_bucket), filtering, and window functions |
timescaledb_analyze_timeseries_<db_id> | Analyze time-series patterns (trend, seasonality summary) for one table/column |
timescaledb_list_hypertables_<db_id> | List hypertables with their time column and dimension count (read-only) |
timescaledb_compression_settings_<db_id> | Show compression configuration for hypertables (read-only) |
timescaledb_retention_policy_<db_id> | Show configured retention policies (read-only) |
timescaledb_list_continuous_aggregates_<db_id> | List continuous aggregates with bucket interval and refresh policy (read-only) |
timescaledb_continuous_aggregate_info_<db_id> | Inspect one continuous aggregate in detail (read-only) |
In unified mode the same seven tools appear once as timescaledb_timeseries_query,
timescaledb_analyze_timeseries, timescaledb_list_hypertables,
timescaledb_compression_settings, timescaledb_retention_policy,
timescaledb_list_continuous_aggregates, and timescaledb_continuous_aggregate_info,
each taking a required database parameter.
Scope note: read-only discovery above goes through the query pipeline and therefore stays usable on
read_onlydatabases; each handler checks for thetimescaledbextension first. Write-policy operations (hypertable creation, compression toggles, add/remove retention or refresh policies) remain unexposed — use plain SQL through the query/execute tools in the meantime. For detailed documentation, see TIMESCALEDB_TOOLS.md.
If you connect many databases (5+), the per-database tool naming generates a large number of tools (5 × N). Some MCP clients — Claude in particular — apply strict limits on the total number of tools and tool description size that can cause the agent to fail to load the server, ignore tools, or refuse to call them. Issue #18 documents this exact symptom: "the db-mcp-server does not function properly with Claude, even though it works fine with OpenAI".
For these clients, launch the server with the --unified-tools flag to register six consolidated tools (query, execute, transaction, performance, explain, describe, schema, filter_tables) instead of per-database tools:
Context-window cost (measured, TestToolTokenBenchmark, re-verified 2026-08 via scripts/token-benchmark.sh): unified mode costs ~1.25–1.6k tokens regardless of how many databases are connected, while per-database mode costs ~800 tokens per database (7 tools each) — 10 connected databases ≈ 8k tokens, an 80% wire-payload saving with unified. With one database only, per-database naming is slightly cheaper; unified wins from two databases onward and scales flat thereafter. Re-measure the real wire payload yourself with scripts/token-benchmark.sh; methodology and results in docs/benchmark-token-efficiency.md.
The transaction_<db_id> tool supports begin, execute, commit, and rollback actions. Each begin returns a transactionId; pass it back to stage statements and to commit or roll back:
Unknown or already-retired transaction IDs return a clear error instead of a silent success, so agents can detect and recover from lost-transaction situations.
query_timeout setting in your configurationEnable verbose logging for troubleshooting:
The project includes comprehensive unit and integration tests for all supported databases.
Run unit tests (no database required):
Integration tests require running database instances. We provide Docker Compose configurations for easy setup.
Test All Databases:
Test Oracle Database:
Test TimescaleDB:
Run comprehensive regression tests across all database types:
All tests run automatically on every pull request via GitHub Actions. The CI pipeline includes:
We welcome contributions to the DB MCP Server project! To contribute:
git checkout -b feature/amazing-feature)git commit -m 'feat: add amazing feature')git push origin feature/amazing-feature)Please see our CONTRIBUTING.md file for detailed guidelines.
Before submitting a pull request, please ensure:
go test -short ./...golangci-lint run ./...This project is licensed under the MIT License - see the LICENSE file for details.