Skip to main content
Glama
andychinghk01

db-query-mcp

README.md
# db-query-mcp

A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for running **read-only SQL queries** across multiple **MySQL** and **PostgreSQL** databases. Built with TypeScript, runnable with [Node.js](https://nodejs.org/), [Bun](https://bun.sh/), or [pnpm](https://pnpm.io/).

Give an AI assistant (Claude Desktop, Copilot, Cursor, Zed, or any MCP-compatible client) safe, read-only access to your databases — without pasting credentials into the chat.

## Features

- 🗄️ **MySQL & PostgreSQL** — mix both engines in one config
- 🔒 **Read-only by design** — only `SELECT`/`SHOW`/`DESCRIBE`/`DESC`/`EXPLAIN`; DML/DDL keywords rejected
- 🔐 **Credentials out of source** — connection config lives in `~/.config/db-query-mcp/config.json`, never in the repo
- ⏱️ **Safety guardrails** — automatic `LIMIT`, per-query timeout, parameterized queries
- 📦 **Installable** — `npx`, `pnpm dlx`, `bunx`, or global install; one binary, no source editing
- 🧩 **Single config, many databases** — each connection can expose multiple databases

## Requirements

- Node.js ≥ 20, Bun, or pnpm (any one)

## Install

### Run without installing (recommended for MCP clients)

```bash
npx db-query-mcp
# or
pnpm dlx db-query-mcp
# or
bunx db-query-mcp
```

### Install globally

```bash
npm install -g db-query-mcp
# or
pnpm add -g db-query-mcp
```

Then run `db-query-mcp` directly.

### From source

```bash
git clone https://github.com/andychinghk01/db-query-mcp.git
cd db-query-mcp
pnpm install
pnpm build
node dist/index.js
```

## Configuration

db-query-mcp reads connections from a JSON config file.

**Path** (first match wins):

1. `DB_QUERY_MCP_CONFIG` env var (absolute path)
2. `~/.config/db-query-mcp/config.json`

### Create the config

```bash
mkdir -p ~/.config/db-query-mcp
cp examples/config.example.json ~/.config/db-query-mcp/config.json
# edit with your real credentials
$EDITOR ~/.config/db-query-mcp/config.json
```

### Schema

```jsonc
{
  "queryTimeoutMs": 30000,   // optional, default 30000
  "defaultRowLimit": 1000,   // optional, default 1000
  "connections": [
    {
      "name": "unique-connection-id",      // shown in list_db
      "description": "Human-readable note",
      "type": "mysql",                      // "mysql" | "postgresql"; defaults to "mysql"
      "host": "db.example.com",
      "port": 3306,
      "username": "readonly-user",
      "password": "your-password",
      "databases": [
        { "name": "actual_db_name", "description": "What this DB contains" }
      ]
    }
  ]
}
```

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `connections` | array | yes | One entry per server you connect to |
| `connections[].type` | `"mysql"` \| `"postgresql"` | no | Defaults to `"mysql"` |
| `connections[].databases` | array | yes | Each becomes a queryable target in `list_db` |
| `queryTimeoutMs` | number | no | Per-query timeout, default 30000 |
| `defaultRowLimit` | number | no | Max rows returned, default 1000 |

> 💡 **Use a dedicated read-only database user.** The server enforces read-only SQL, but defense in depth matters — grant only `SELECT` (and `SHOW`/`EXPLAIN` where needed) to the user in this config.

## MCP client configuration

Add the server to your MCP client config.

### Claude Desktop / Claude Code (`claude_desktop_config.json` or `.mcp.json`)

```json
{
  "mcpServers": {
    "db-query-mcp": {
      "command": "npx",
      "args": ["db-query-mcp"]
    }
  }
}
```

### With Bun

```json
{
  "mcpServers": {
    "db-query-mcp": {
      "command": "bunx",
      "args": ["db-query-mcp"]
    }
  }
}
```

### With pnpm

```json
{
  "mcpServers": {
    "db-query-mcp": {
      "command": "pnpm",
      "args": ["dlx", "db-query-mcp"]
    }
  }
}
```

### Custom config path

```json
{
  "mcpServers": {
    "db-query-mcp": {
      "command": "npx",
      "args": ["db-query-mcp"],
      "env": { "DB_QUERY_MCP_CONFIG": "/custom/path/config.json" }
    }
  }
}
```

## Tools

### `list_db`

Lists every configured database with its connection name, engine type, host, port, and description. No arguments.

### `query`

Executes a read-only query.

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `dbName` | string | yes | Database name from `list_db` |
| `sql` | string | yes | Read-only SQL statement |
| `params` | array | no | Positional parameters — `?` for MySQL, `$1, $2, ...` for PostgreSQL |

## Safety guardrails

- **Statement allowlist** — only `SELECT`, `SHOW`, `DESCRIBE`, `DESC`, `EXPLAIN` may start a query.
- **Keyword denylist** — `INSERT`, `UPDATE`, `DELETE`, `DROP`, `ALTER`, `CREATE`, `TRUNCATE`, `REPLACE`, `MERGE`, `CALL`, `EXEC`, `GRANT`, `REVOKE`, `LOCK`, `UNLOCK`, `LOAD DATA` are rejected anywhere in the statement (after comment/quote normalization).
- **Row limit** — `SELECT`s are wrapped as subselects and capped at `defaultRowLimit` (default 1000).
- **Timeout** — queries abort after `queryTimeoutMs` (default 30s).
- **Parameterized queries** — use `?` (MySQL) or `$1` (Postgres) placeholders; values never interpolated into SQL.

These guardrails reduce risk but are not a substitute for least-privilege database permissions. Always pair this server with a read-only DB user.

## Development

```bash
pnpm install
pnpm build      # tsc -> dist/
pnpm dev        # watch mode
pnpm start      # node dist/index.js
pnpm start:bun  # bun dist/index.js
```

## License

MIT © Andy Ching

TDQS

A4.2/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct roles: list_db for discovery and query for executing SQL. There is no overlap in their purposes or outputs.

Naming Consistency4/5

Both tools use a verb-first pattern, but list_db is verb_noun while query is just a verb. This is a minor deviation and still predictable.

Tool Count3/5

With only 2 tools, the set feels thin, though each earns its place for the stated read-only query purpose. The count is at the lower boundary of typical MCP servers.

Completeness5/5

The tool surface fully covers the domain of read-only database querying: listing available databases and executing arbitrary SELECT/SHOW/DESCRIBE/EXPLAIN statements. No critical gaps exist.

Maintenance

ActivitySlowing
ResponsivenessNo issues