{
  "markdown": "# Database MCP\n\n[![CI](https://github.com/haymon-ai/dbmcp/actions/workflows/ci.yml/badge.svg)](https://github.com/haymon-ai/dbmcp/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/haymon-ai/dbmcp)](https://github.com/haymon-ai/dbmcp/releases/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Docs](https://img.shields.io/badge/docs-dbmcp.haymon.ai-black)](https://dbmcp.haymon.ai/docs/)\n\nA single-binary [MCP](https://modelcontextprotocol.io/) server for SQL databases. Connect your AI assistant to MySQL/MariaDB, PostgreSQL, or SQLite with zero runtime dependencies.\n\n**[Website](https://dbmcp.haymon.ai)** · **[Documentation](https://dbmcp.haymon.ai/docs/)** · **[Releases](https://github.com/haymon-ai/dbmcp/releases)**\n\n![demo](https://raw.githubusercontent.com/haymon-ai/dbmcp/master/docs/public/demo.gif)\n\n## Features ✨\n\n- **Multi-database** — MySQL/MariaDB, PostgreSQL, and SQLite from one binary\n- **MCP tools** — schema discovery (`listDatabases`, `listTables`, `listViews`, `listTriggers`, `listFunctions`, `listProcedures`, `listMaterializedViews`), data access (`readQuery`, `writeQuery`), DDL (`createDatabase`, `dropDatabase`, `dropTable`), and `explainQuery`. Read-only mode hides the write tools (`writeQuery`, `createDatabase`, `dropDatabase`, `dropTable`). See [MCP Tools](#mcp-tools) for per-backend availability.\n- **Single binary** — ~7 MB, no Python/Node/Docker needed\n- **Multiple transports** — stdio (for Claude Desktop, Cursor) and HTTP (for remote/multi-client)\n- **Two-layer config** — CLI flags > environment variables, with sensible defaults per backend\n\n## Install 📦\n\n**macOS, Linux, WSL**:\n\n```bash\ncurl -fsSL https://dbmcp.haymon.ai/install.sh | bash\n```\n\n**Windows PowerShell**:\n\n```powershell\nirm https://dbmcp.haymon.ai/install.ps1 | iex\n```\n\n**Windows CMD**:\n\n```batch\ncurl -fsSL https://dbmcp.haymon.ai/install.cmd -o install.cmd && install.cmd && del install.cmd\n```\n\nSee the [installation docs](https://dbmcp.haymon.ai/docs/installation) for Docker, Cargo, and other methods.\n\n## Quick Start 🚀\n\n### Using `.mcp.json` (recommended)\n\nAdd a `.mcp.json` file to your project root. MCP clients read this file and configure the server automatically.\n\n**Stdio transport** — the client starts and manages the server process:\n\n```json\n{\n  \"mcpServers\": {\n    \"dbmcp\": {\n      \"command\": \"dbmcp\",\n      \"args\": [\"stdio\"],\n      \"env\": {\n        \"DB_BACKEND\": \"mysql\",\n        \"DB_HOST\": \"127.0.0.1\",\n        \"DB_PORT\": \"3306\",\n        \"DB_USER\": \"root\",\n        \"DB_PASSWORD\": \"secret\",\n        \"DB_NAME\": \"mydb\"\n      }\n    }\n  }\n}\n```\n\n**HTTP transport** — you start the server yourself, the client connects to it:\n\n```bash\n# Start the server first\ndbmcp http --db-backend mysql --db-user root --db-name mydb --port 9001\n```\n\n```json\n{\n  \"mcpServers\": {\n    \"dbmcp\": {\n      \"type\": \"http\",\n      \"url\": \"http://127.0.0.1:9001/mcp\"\n    }\n  }\n}\n```\n\n> **Note:** The `\"type\": \"http\"` field is required for HTTP transport. Without it, clients like Claude Code will reject the config.\n\n### Using CLI flags\n\n```bash\n# MySQL/MariaDB\ndbmcp stdio --db-backend mysql --db-host localhost --db-user root --db-name mydb\n\n# PostgreSQL\ndbmcp stdio --db-backend postgres --db-host localhost --db-user postgres --db-name mydb\n\n# SQLite\ndbmcp stdio --db-backend sqlite --db-name ./data.db\n\n# HTTP transport\ndbmcp http --db-backend mysql --db-user root --db-name mydb --host 0.0.0.0 --port 9001\n```\n\n### Using environment variables\n\n```bash\nDB_BACKEND=mysql DB_USER=root DB_NAME=mydb dbmcp stdio\n```\n\n## Configuration ⚙️\n\nConfiguration is loaded with clear precedence:\n\n**CLI flags > environment variables > defaults**\n\nEnvironment variables are typically set by your MCP client (via `env` or `envFile` in the server config).\n\n### Subcommands\n\n| Subcommand | Description |\n|------------|-------------|\n| `stdio` | Run in stdio mode |\n| `http` | Run in HTTP/SSE mode |\n| `version` | Print version information and exit |\n\nA subcommand is required — running `dbmcp` with no subcommand prints usage help and exits with a non-zero status.\n\n### Database Options (shared across subcommands)\n\n| Flag | Env Variable | Default | Description |\n|------|-------------|---------|-------------|\n| `--db-backend` | `DB_BACKEND` | *(required)* | `mysql`, `mariadb`, `postgres`, or `sqlite` |\n| `--db-host` | `DB_HOST` | `localhost` | Database host |\n| `--db-port` | `DB_PORT` | backend default | `3306` (MySQL/MariaDB), `5432` (PostgreSQL) |\n| `--db-user` | `DB_USER` | backend default | `root` (MySQL/MariaDB), `postgres` (PostgreSQL) |\n| `--db-password` | `DB_PASSWORD` | *(empty)* | Database password |\n| `--db-name` | `DB_NAME` | *(empty)* | Database name or SQLite file path |\n| `--db-charset` | `DB_CHARSET` | | Character set (MySQL/MariaDB only) |\n\n### SSL/TLS Options\n\n| Flag | Env Variable | Default | Description |\n|------|-------------|---------|-------------|\n| `--db-ssl` | `DB_SSL` | `false` | Enable SSL |\n| `--db-ssl-ca` | `DB_SSL_CA` | | CA certificate path |\n| `--db-ssl-cert` | `DB_SSL_CERT` | | Client certificate path |\n| `--db-ssl-key` | `DB_SSL_KEY` | | Client key path |\n| `--db-ssl-verify-cert` | `DB_SSL_VERIFY_CERT` | `true` | Verify server certificate |\n\n### Server Options\n\n| Flag | Env Variable | Default | Description |\n|------|-------------|---------|-------------|\n| `--db-read-only` | `DB_READ_ONLY` | `true` | Block write queries |\n| `--db-max-pool-size` | `DB_MAX_POOL_SIZE` | `5` | Max connection pool size (min: 1) |\n| `--db-connection-timeout` | `DB_CONNECTION_TIMEOUT` | *(unset)* | Connection timeout in seconds (min: 1) |\n| `--db-query-timeout` | `DB_QUERY_TIMEOUT` | `30` | Query execution timeout in seconds |\n| `--db-page-size` | `DB_PAGE_SIZE` | `100` | Max items per paginated tool response (range 1–500) |\n\n### Logging Options\n\n| Flag | Env Variable | Default | Description |\n|------|-------------|---------|-------------|\n| `--log-level` | `LOG_LEVEL` | `info` | Log level (trace/debug/info/warn/error) |\n\n### HTTP-only Options (only available with `http` subcommand)\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `--host` | `127.0.0.1` | Bind host |\n| `--port` | `9001` | Bind port |\n| `--allowed-origins` | localhost variants | Allowed browser origins (comma-separated). Drives both CORS preflight and server-side Origin rejection. |\n| `--allowed-hosts` | `localhost,127.0.0.1,::1` | Trusted Host headers (comma-separated). Enforced server-side; HTTP/2 `:authority` is honored. |\n\n## MCP Tools 🧩\n\n### listDatabases\n\nLists accessible databases, paginated via `cursor` / `nextCursor`. See [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details. Not available for SQLite.\n\n### listTables\n\nLists tables in a database, paginated via `cursor` / `nextCursor`. See [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details.\n\nParameters: `database` (defaults to the active database; SQLite has no `database` parameter), `cursor`, `search`, `detailed`.\n\n`search` is an optional case-insensitive `LIKE`/`ILIKE` pattern with `%` (any sequence) and `_` (single character) as wildcards — pass `users%` to match names beginning with `users`, or `%order%` for substring matching. A bare word with no wildcards matches only an exact table name.\n\n`detailed` (default `false`) switches the response shape:\n\n- **Brief** (default) — `tables` is a sorted JSON array of bare table-name strings.\n- **Detailed** (`detailed: true`) — `tables` is a JSON object keyed by table name; each value carries the table's `schema`, `kind`, `owner`, `comment`, `columns[]`, `constraints[]`, `indexes[]`, and `triggers[]`. One call returns both the table list and the per-table metadata.\n\n### listViews\n\nLists views in a database, paginated via `cursor` / `nextCursor`. Available on MySQL/MariaDB, PostgreSQL (`public` schema), and SQLite. Parameters: `database` (defaults to the active database; SQLite has no `database` parameter), `cursor`, `search`, `detailed`. SQLite returns the brief shape only — `search` and `detailed` are not accepted there.\n\n`search` is an optional case-insensitive `LIKE`/`ILIKE` pattern with `%` (any sequence) and `_` (single character) as wildcards. The `search` value must remain identical across paginated calls for cursor continuity.\n\n`detailed` (default `false`) switches the response shape:\n\n- **Brief** (default) — `views` is a sorted JSON array of bare view-name strings. View names are unique per schema, so no duplicates appear.\n- **Detailed** (`detailed: true`) — `views` is a JSON object keyed by bare view name; each value carries the per-backend metadata payload. PostgreSQL exposes `schema`, `owner`, `description`, `definition`. MySQL/MariaDB exposes `schema`, `definer`, `security`, `checkOption`, `updatable`, `characterSetClient`, `collationConnection`, `definition`. See the [`listViews` reference](https://dbmcp.haymon.ai/docs/features#listviews) for source columns, enumerated value sets, and intentional omissions per backend.\n\nSee [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details.\n\n### listTriggers\n\nLists user-defined triggers on tables, paginated via `cursor` / `nextCursor`. Internal constraint and foreign-key triggers are excluded. Available on MySQL/MariaDB, PostgreSQL (`public` schema), and SQLite. Parameters: `database` (defaults to the active database; SQLite has no `database` parameter), `cursor`, `search`, `detailed`.\n\n`search` is an optional case-insensitive `LIKE`/`ILIKE` pattern with `%` (any sequence) and `_` (single character) as wildcards. The `search` value must remain identical across paginated calls for cursor continuity.\n\n`detailed` (default `false`) switches the response shape:\n\n- **Brief** (default) — `triggers` is a sorted JSON array of bare trigger-name strings.\n- **Detailed** (`detailed: true`) — `triggers` is a JSON object keyed by trigger name; each value carries the per-backend metadata payload (timing, events, definition, and backend-specific extras like PostgreSQL `status`/`functionName` or MySQL/MariaDB session-context fields). See the [`listTriggers` reference](https://dbmcp.haymon.ai/docs/features#listtriggers) for the full per-backend field list.\n\nSee [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details.\n\n### listFunctions\n\nLists user-defined SQL functions, paginated via `cursor` / `nextCursor`. PostgreSQL excludes aggregates, window functions, and procedures; MySQL/MariaDB excludes loadable UDFs (`mysql.func`). Available on MySQL/MariaDB and PostgreSQL (`public` schema). Not available for SQLite. Parameters: `database` (defaults to the active database), `cursor`, `search`, `detailed`.\n\n`search` is an optional case-insensitive `LIKE`/`ILIKE` pattern with `%` (any sequence) and `_` (single character) as wildcards. The `search` value must remain identical across paginated calls for cursor continuity.\n\n`detailed` (default `false`) switches the response shape:\n\n- **Brief** (default) — `functions` is a sorted JSON array of bare function-name strings. PostgreSQL overloads appear once per overload (duplicate name strings are expected).\n- **Detailed** (`detailed: true`) — `functions` is a JSON object keyed by function signature; each value carries the per-backend metadata payload (language, arguments, return type, definition, and backend-specific extras such as PostgreSQL `volatility`/`strict`/`parallelSafety` or MySQL/MariaDB session-context fields). PostgreSQL keys are `name(arguments)` (overloads disambiguate); MySQL/MariaDB keys are bare names (no overloading). See the [`listFunctions` reference](https://dbmcp.haymon.ai/docs/features#listfunctions) for the full per-backend field list.\n\nSee [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details.\n\n### listProcedures\n\nLists user-defined stored procedures, paginated via `cursor` / `nextCursor`. Available on MySQL/MariaDB and PostgreSQL (`public` schema, PostgreSQL 11+). Not available for SQLite. Parameters: `database` (defaults to the active database), `cursor`, `search`, `detailed`.\n\n`search` is an optional case-insensitive `LIKE`/`ILIKE` pattern with `%` (any sequence) and `_` (single character) as wildcards. The `search` value must remain identical across paginated calls for cursor continuity.\n\n`detailed` (default `false`) switches the response shape:\n\n- **Brief** (default) — `procedures` is a sorted JSON array of bare procedure-name strings. PostgreSQL overloads appear once per overload (duplicate name strings are expected).\n- **Detailed** (`detailed: true`) — `procedures` is a JSON object keyed by procedure signature; each value carries the per-backend metadata payload (language, arguments, security, definition, and backend-specific extras such as PostgreSQL `owner` or MySQL/MariaDB `deterministic`/`sqlDataAccess`/session-context fields). PostgreSQL keys are `name(arguments)` (overloads disambiguate; zero-arg procedures key as `name()`); MySQL/MariaDB keys are bare names (no overloading). See the [`listProcedures` reference](https://dbmcp.haymon.ai/docs/features#listprocedures) for the full per-backend field list.\n\nSee [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details.\n\n### listMaterializedViews\n\nLists materialized views in the `public` schema, paginated via `cursor` / `nextCursor`. PostgreSQL only — not available for MySQL/MariaDB or SQLite. Parameters: `database` (defaults to the active database), `cursor`, `search`, `detailed`.\n\n`search` is an optional case-insensitive `ILIKE` pattern with `%` (any sequence) and `_` (single character) as wildcards. SQL meta-characters (`'`, `;`, `--`) are bound as parameter values and never interpolated. The `search` value must remain identical across paginated calls for cursor continuity.\n\n`detailed` (default `false`) switches the response shape:\n\n- **Brief** (default) — `materializedViews` is a sorted JSON array of bare matview-name strings. Matview names are unique per schema, so no duplicates appear.\n- **Detailed** (`detailed: true`) — `materializedViews` is a JSON object keyed by bare matview name; each value carries `schema`, `owner`, `description` (or `null` when no `COMMENT ON MATERIALIZED VIEW`), `definition` (the SELECT body verbatim from `pg_matviews.definition`), `populated` (`false` for matviews created `WITH NO DATA` and never refreshed), and `indexed` (`true` when at least one index exists; `REFRESH MATERIALIZED VIEW CONCURRENTLY` additionally requires a unique index). Detailed mode deliberately omits column metadata, `tablespace`, storage parameters, and unique-index detection — recoverable via `definition`, `listTables(detailed=true)`, or `readQuery` against `pg_indexes`. See the [`listMaterializedViews` reference](https://dbmcp.haymon.ai/docs/features#listmaterializedviews) for source columns and operational semantics.\n\nSee [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details.\n\n### readQuery\n\nExecutes a read-only SQL query (SELECT, SHOW, DESCRIBE, USE, EXPLAIN). Always enforces SQL validation as defence-in-depth. Parameters: `query`, `database`, `cursor`. `SELECT` results paginate via `cursor` / `nextCursor`; `SHOW`, `DESCRIBE`, `USE`, and `EXPLAIN` return a single page and ignore `cursor`. See [Cursor Pagination](https://dbmcp.haymon.ai/docs/features#cursor-pagination) for iteration details.\n\n### writeQuery\n\nExecutes a write SQL query (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP). Only available when read-only mode is disabled. Parameters: `query`, `database`.\n\n### createDatabase\n\nCreates a database if it doesn't exist. Only available when read-only mode is disabled. Not available for SQLite. Parameters: `database`.\n\n### dropDatabase\n\nDrops an existing database. Refuses to drop the currently connected database. Only available when read-only mode is disabled. Not available for SQLite. Parameters: `database`.\n\n### dropTable\n\nDrops a table from a database. If the table has foreign key dependents, the database error is surfaced to the user. On PostgreSQL, a `cascade` parameter is available to force the drop with `CASCADE`. Only available when read-only mode is disabled. Parameters: `database`, `table`, `cascade` (PostgreSQL only).\n\n### explainQuery\n\nReturns the execution plan for a SQL query. Supports an optional `analyze` parameter for actual execution statistics (PostgreSQL and MySQL/MariaDB). In read-only mode, EXPLAIN ANALYZE is only allowed for read-only statements since it actually executes the query. SQLite uses EXPLAIN QUERY PLAN (no ANALYZE support). Always available regardless of read-only mode. Parameters: `query`, `database`, `analyze` (PostgreSQL/MySQL only).\n\n## Security 🔒\n\n- **Read-only mode** (default) — write tools hidden from AI assistant; `readQuery` enforces AST-based SQL validation\n- **Single-statement enforcement** — multi-statement injection blocked at parse level\n- **Dangerous function blocking** — `LOAD_FILE()`, `INTO OUTFILE`, `INTO DUMPFILE` detected in the AST\n- **Identifier validation** — database/table names validated against control characters and empty strings\n- **Origin + Host allowlists** — server-side rejection (403) plus CORS preflight; configurable for HTTP transport\n- **SSL/TLS** — configured via individual `DB_SSL_*` variables\n- **PII redaction** *(opt-in, off by default)* — when enabled, query tool output passes through a regex-based redactor that rewrites detected PII spans across **46 built-in entity types** spanning seven categories: personal (email), financial (cards, IBAN, UK bank accounts, sort and US ABA routing codes, CVV), government IDs (SSN, ITIN, EIN, UK/US passports, NHS, NINO, SIN, VAT), contact (phone), network (IP, URL, MAC), digital identity (API keys, JWTs, PEM private keys, password hashes), and crypto wallets. Toggle: `--pii` / `PII_ENABLE`. Operator: `--pii-operator` / `PII_OPERATOR` — one of `replace` (default, entity-aware placeholders like `<EMAIL_ADDRESS>`), `mask` (length-preserving `*`), `redact` (drop), `hash` (SHA-256 hex). Optional subset via `--pii-categories` / `PII_CATEGORIES` (comma-separated, e.g. `financial,government`); unset enables all built-ins. Scope: query tool output payloads only. See [PII configuration](https://dbmcp.haymon.ai/docs/configuration#pii) for the full surface.\n- **ML/NER redaction** *(opt-in at runtime, off by default)* — adds `PERSON`, `LOCATION`, `ORGANIZATION`, `NATIONALITY_RELIGION_POLITICS`, and `FACILITY` detection that regex cannot catch, enabled via the `--pii-ner` / `PII_NER_ENABLE` toggle plus a user-supplied model directory. Which entities are produced depends on the model's labels (CoNLL models give person/location/organization; OntoNotes-class models add NRP and facility). Inference uses **ONNX Runtime** (model directory holds `config.json`, `tokenizer.json`, `model.onnx`; recommended: the MIT-licensed [`dslim/bert-base-NER`](https://huggingface.co/dslim/bert-base-NER) exported to ONNX, int8-quantized for speed). Fail-closed: a model that cannot load aborts startup and an inference error fails the request — never a silent fallback. Respects `--pii-categories`. English for v1.\n- **Credential redaction** — database password is never shown in logs or debug output\n\n## Testing 🧪\n\n```bash\n# Unit tests\ncargo test --workspace --lib --bins\n\n# Integration tests (requires Docker)\n./tests/run.sh\n\n# Filter by engine\n./tests/run.sh --filter mariadb\n./tests/run.sh --filter mysql\n./tests/run.sh --filter postgres\n./tests/run.sh --filter sqlite\n\n# With MCP Inspector\nnpx @modelcontextprotocol/inspector ./target/release/dbmcp stdio\n\n# HTTP mode testing\ncurl -X POST http://localhost:9001/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"0.1\"}}}'\n```\n\n## Project Structure 🗂️\n\nThis is a Cargo workspace with the following crates:\n\n| Crate | Path | Description |\n|-------|------|-------------|\n| `dbmcp` | `.` (root) | Main binary — CLI, transports, database backends |\n| `dbmcp-sql` | `crates/backend/` | Shared error types, validation, and identifier utilities |\n| `dbmcp-config` | `crates/config/` | Configuration structs and CLI argument mapping |\n| `dbmcp-server` | `crates/server/` | Shared MCP tool implementations and server info |\n| `dbmcp-mysql` | `crates/mysql/` | MySQL/MariaDB backend handler and operations |\n| `dbmcp-postgres` | `crates/postgres/` | PostgreSQL backend handler and operations |\n| `dbmcp-sqlite` | `crates/sqlite/` | SQLite backend handler and operations |\n| `sqlx-json` | `crates/sqlx-json/` | Type-safe row-to-JSON conversion for sqlx (`RowExt` trait) |\n\n## Development 🧰\n\n```bash\ncargo build              # Development build\ncargo build --release    # Release build (~7 MB)\ncargo test               # Run tests\ncargo clippy --workspace --tests -- -D warnings  # Lint\ncargo fmt                # Format\ncargo doc --no-deps      # Build documentation\n```\n\n## License 📄\n\nThis project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.\n",
  "bytes": 21277,
  "sha": "1692fa7fc54c382d58fd68c50e347f3c33111510830eb1cd90faf8cd71abbbe1",
  "repo_slug": "haymon-ai/database",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_ai_haymon_database_2b3cda47/readme"
}