Skip to main content
Glama
vinycoolguy2015

Database Assistant MCP Server

README.md
# Database Assistant MCP Server

A read-only MCP (Model Context Protocol) server for database exploration and querying. Connect any MCP-compatible client (AWS Kiro, Claude Desktop, etc.) to your PostgreSQL or MySQL database and explore schemas, run queries, generate SQL from natural language, and export results as CSV.

## Features

- **Schema Discovery** — List databases, schemas, tables, columns, constraints, indexes, and foreign key relationships
- **Safe Query Execution** — AST-based SQL validation ensures only read-only queries run
- **Natural Language to SQL** — Describe what you want in plain English and get a validated SQL query
- **CSV Export** — Export any query result to a CSV file
- **Query Explanation** — Run EXPLAIN ANALYZE to understand query performance
- **Pagination** — Large results are paginated (100 rows/page) automatically
- **Audit Logging** — Every query is logged with timestamp, execution time, and row count

## Tools

| Tool | Description |
|------|-------------|
| `list_databases` | List all databases on the server |
| `list_schemas` | List schemas (filtered by allowlist) |
| `list_tables` | Tables in a schema with types and row counts |
| `describe_table` | Columns, types, constraints, and indexes |
| `describe_relationships` | Foreign key tree (incoming + outgoing) |
| `sample_data` | Quick N-row preview of a table |
| `validate_sql` | Check if a query is safe before running |
| `run_sql` | Execute a validated read-only query |
| `explain_query` | EXPLAIN ANALYZE with execution plan |
| `generate_sql` | Natural language → SQL (LLM-powered) |
| `export_csv` | Execute query and save results as CSV |

## Security

This server enforces strict read-only access:

- **AST-based validation** — SQL is parsed into an abstract syntax tree using [sqlglot](https://github.com/tobymao/sqlglot), not regex
- **Blocked operations** — INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE, GRANT, REVOKE, COPY, CALL
- **Single-statement only** — Multi-statement queries (`;` separated) are rejected
- **Dangerous function blocking** — `pg_read_file`, `lo_export`, `dblink`, `LOAD_FILE`, etc.
- **Automatic LIMIT** — Queries without a LIMIT get one injected (default: 1000 rows max)
- **Query timeout** — Enforced at the database level (default: 10 seconds)
- **Schema allowlist** — Restrict access to specific schemas only
- **Generated SQL re-validation** — LLM-generated queries pass through the same validator

## Prerequisites

- Python 3.10+
- [uv](https://docs.astral.sh/uv/) package manager
- PostgreSQL or MySQL database

## Setup

1. **Clone and install dependencies:**

```bash
cd /path/to/RDS
uv sync
```

2. **Configure environment:**

```bash
cp .env.example .env
# Edit .env with your database credentials
```

3. **Seed a test database (optional):**

```bash
psql -U postgres -f seed.sql
```

This creates an `ecommerce` database with 50 tables and ~25,000 rows across customers, products, orders, analytics, support, and more.

## Configuration

Set these environment variables (via `.env` file or system environment):

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `DB_HOST` | Yes | — | Database hostname or RDS endpoint |
| `DB_PORT` | No | `5432` | Database port |
| `DB_NAME` | Yes | — | Database name |
| `DB_USER` | Yes | — | Database user (use a read-only user) |
| `DB_PASSWORD` | Yes | — | Database password |
| `DB_TYPE` | No | `postgresql` | `postgresql` or `mysql` |
| `ALLOWED_SCHEMAS` | No | (all) | Comma-separated schema allowlist |
| `QUERY_TIMEOUT` | No | `10` | Max query execution time (seconds) |
| `MAX_ROWS` | No | `1000` | Maximum rows returned per query |
| `CSV_EXPORT_DIR` | No | `/tmp/db_exports` | Directory for CSV exports |
| `OPENAI_BASE_URL` | No | — | LLM API endpoint (for `generate_sql`) |
| `OPENAI_API_KEY` | No | — | LLM API key (for `generate_sql`) |
| `MODEL` | No | `bedrock.claude-sonnet-4-6` | LLM model ID |

## Usage

### With AWS Kiro

Add to your Kiro MCP configuration:

```json
{
  "mcpServers": {
    "database-assistant": {
      "command": "/opt/homebrew/bin/uv",
      "args": ["run", "--directory", "/path/to/database_mcp_server", "mcp_server.py"],
      "env": {
        "DB_HOST": "your-rds-endpoint.rds.amazonaws.com",
        "DB_PORT": "5432",
        "DB_NAME": "ecommerce",
        "DB_USER": "readonly_user",
        "DB_PASSWORD": "your_password",
        "DB_TYPE": "postgresql",
        "ALLOWED_SCHEMAS": "store"
      }
    }
  }
}
```

### With Claude Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "database-assistant": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/RDS", "mcp_server.py"]
    }
  }
}
```

### With MCP Inspector (for testing)

```bash
uv run mcp dev mcp_server.py
```

### Direct stdio (for development)

```bash
uv run mcp_server.py
```

## Example Workflows

### Explore a database schema

```
User: What tables are in this database?
→ list_tables(schema="store")

User: Tell me about the orders table
→ describe_table(table="store.orders")

User: What relates to orders?
→ describe_relationships(table="store.orders")
```

### Query with natural language

```
User: Show me the top 10 customers by revenue this year
→ generate_sql(question="top 10 customers by total order revenue in 2024")
→ validate_sql(query="SELECT ...")
→ run_sql(query="SELECT ...")
```

### Export data

```
User: Export all orders from last month as CSV
→ generate_sql(question="all orders created in the last 30 days with customer name and total")
→ export_csv(query="SELECT ...")
→ Returns: /tmp/db_exports/export_20240715_143022_a1b2c3d4.csv
```

## Architecture

```
MCP Client (Kiro / Claude Desktop)
        │
        ▼ (stdio)
┌─────────────────────────────┐
│      mcp_server.py          │  FastMCP server, 11 tools
├─────────────────────────────┤
│  sql/validator.py           │  AST-based safety validation (sqlglot)
│  sql/generator.py           │  NL→SQL via OpenAI-compatible LLM
│  db/schema.py               │  Schema introspection service
│  db/connection.py           │  Async connection pool (asyncpg/aiomysql)
│  export/csv_export.py       │  CSV file generation
│  config.py                  │  Environment-based configuration
└─────────────────────────────┘
        │
        ▼
   PostgreSQL / MySQL / AWS RDS
```

## Project Structure

```
.
├── mcp_server.py          # MCP server entry point with tool definitions
├── config.py              # Configuration from environment variables
├── db/
│   ├── connection.py      # Async connection manager with pooling
│   └── schema.py          # Schema introspection service
├── sql/
│   ├── validator.py       # SQL validation (sqlglot AST)
│   └── generator.py       # LLM-based SQL generation
├── export/
│   └── csv_export.py      # CSV export utility
├── seed.sql               # Sample database (50 tables, 25k+ rows)
├── pyproject.toml         # Dependencies and project metadata
├── .env.example           # Environment variable template
└── .gitignore
```

## Creating a Read-Only Database User

For production use, create a dedicated read-only user:

```sql
-- PostgreSQL
CREATE USER readonly_user WITH PASSWORD 'secure_password';
GRANT CONNECT ON DATABASE ecommerce TO readonly_user;
GRANT USAGE ON SCHEMA store TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA store TO readonly_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA store GRANT SELECT ON TABLES TO readonly_user;
```

```sql
-- MySQL
CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'secure_password';
GRANT SELECT ON ecommerce.* TO 'readonly_user'@'%';
FLUSH PRIVILEGES;
```

## Dependencies

- [mcp](https://pypi.org/project/mcp/) — Model Context Protocol SDK
- [sqlglot](https://github.com/tobymao/sqlglot) — SQL parser for validation
- [asyncpg](https://github.com/MagicStack/asyncpg) — Async PostgreSQL driver
- [aiomysql](https://github.com/aio-libs/aiomysql) — Async MySQL driver
- [openai](https://github.com/openai/openai-python) — LLM API client (for SQL generation)
- [python-dotenv](https://github.com/theskumar/python-dotenv) — Environment variable loading
- [pydantic](https://github.com/pydantic/pydantic) — Data validation

## License

MIT

TDQS

A4/5.0

Scored across 11 tools

Disambiguation5/5

Each tool has a clearly distinct purpose covering schema browsing, querying, validation, and export. There is no overlap or ambiguity between tools.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern using snake_case, making them predictable and easy to navigate.

Tool Count5/5

11 tools provide comprehensive coverage for database exploration and safe querying without being excessive or sparse.

Completeness4/5

Covers essential CRUD-like operations for a read-only assistant, but lacks a direct row count tool and alternative export formats like JSON.

Maintenance

ActivityStale
ResponsivenessNo issues