Metadata-Version: 2.5
Name: mcp-database-universal
Version: 0.1.3
Summary: MCP Database Server — reasoning interface for databases, not a thin wrapper
Project-URL: Homepage, https://github.com/kobramantra-debug/mcp-database-server
Project-URL: Repository, https://github.com/kobramantra-debug/mcp-database-server
Project-URL: Issues, https://github.com/kobramantra-debug/mcp-database-server/issues
Author: mcp-database-universal contributors
License-Expression: MIT
Keywords: ai-tools,database,mcp,model-context-protocol,mysql,postgresql,sqlite
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: mcp[cli]>=2.0.0
Provides-Extra: all
Requires-Dist: psycopg[binary]>=3.1.0; extra == 'all'
Requires-Dist: pymysql>=1.1.0; extra == 'all'
Requires-Dist: pyodbc>=5.1.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Provides-Extra: mssql
Requires-Dist: pyodbc>=5.1.0; extra == 'mssql'
Provides-Extra: mysql
Requires-Dist: pymysql>=1.1.0; extra == 'mysql'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1.0; extra == 'postgres'
Description-Content-Type: text/markdown

# MCP Database Server

A reasoning interface for databases for MCP-capable AI agents — not a thin SQL wrapper.

`mcp-database-universal` gives AI agents a set of **7 reasoning tools** to explore and query a database safely, understand its schema and data shape, run natural-language questions, and visualize relationships — all without exposing raw connection internals.

## Features

- **7 reasoning tools** designed for AI agents: test connection, list tables, inspect a table, run parameterized SQL, ask questions in plain language, profile data, and render an ER diagram.
- **Multi-engine**: SQLite (built-in) plus optional PostgreSQL, MySQL, and MSSQL.
- **Safety first**: read-only by default, parameterized queries, statement validation, row/time/output limits.
- **LLM-friendly output**: types translated, `NULL`s handled, results formatted in Markdown tables with context.
- **Schema introspection**: auto-discover tables, columns, indexes, foreign keys, and relationships.
- **Natural language queries**: translate plain-text questions into SQL and return results.

## Supported engines

| Engine      | Requirement    | Install extra                    |
|-------------|----------------|----------------------------------|
| SQLite      | built-in       | —                                |
| PostgreSQL  | psycopg        | `pip install "mcp-database-universal[postgres]"` |
| MySQL       | PyMySQL        | `pip install "mcp-database-universal[mysql]"`     |
| MSSQL       | pyodbc + ODBC driver | `pip install "mcp-database-universal[mssql]"`     |
| all         | —              | `pip install "mcp-database-universal[all]"`       |

## Install

```bash
pip install mcp-database-universal

# With optional engines:
pip install "mcp-database-universal[postgres]"
pip install "mcp-database-universal[mysql]"
pip install "mcp-database-universal[mssql]"
# or everything:
pip install "mcp-database-universal[all]"
```

## Quick start

Run the server over STDIO (the default transport for MCP clients):

```bash
DATABASE_URL=sqlite:///app.db python -m mcp_database_universal
```

Connection URLs:

```
sqlite:///path/to/db.db              SQLite (file)
sqlite:///:memory:                   SQLite (in-memory)
postgresql://user:pass@host:5432/db  PostgreSQL
mysql://user:pass@host:3306/db       MySQL
mssql://user:pass@host:1433/db       MSSQL (uses ODBC Driver 18)
```

## Docker

```bash
docker build -t mcp-db .

# Mount a SQLite database read-only:
docker run --rm -i \
  -v /host/path/app.db:/data/app.db:ro \
  -e DATABASE_URL=sqlite:////data/app.db \
  mcp-db

# Or in-memory:
docker run --rm -i -e DATABASE_URL=sqlite:///:memory: mcp-db
```

## Configuration

All configuration is done through environment variables.

| Variable                    | Default   | Description                                            |
|-----------------------------|-----------|--------------------------------------------------------|
| `DATABASE_URL`              | *(required)* | Database connection URL.                            |
| `DATABASE_READ_ONLY`        | `true`    | Enforce read-only mode (blocks writes even if `DATABASE_WRITE_ENABLED`). |
| `DATABASE_WRITE_ENABLED`    | `false`   | Allow write statements when `DATABASE_READ_ONLY=false`. |
| `DATABASE_MAX_ROWS`         | `1000`    | Maximum rows returned per query.                       |
| `DATABASE_MAX_QUERY_TIME`   | `30`      | Query timeout in seconds.                              |
| `DATABASE_MAX_OUTPUT_BYTES` | `50000`   | Cap on result payload size.                            |
| `DATABASE_SAMPLE_SIZE`      | `5`       | Number of sample rows shown in table/column stats.     |
| `DATABASE_PROFILE_TOP_N`    | `10`      | Top-N value distribution entries in profiling.         |
| `OPENAI_API_KEY`            | —         | API key for the LLM-backed `natural_query` (OpenAI).            |
| `ANTHROPIC_API_KEY`         | —         | API key for the LLM-backed `natural_query` (Anthropic).         |

## Tools

| Tool               | Description                                                        |
|--------------------|--------------------------------------------------------------------|
| `test_connection`  | Test DB connectivity; report engine, version, name, size, table count. |
| `list_tables`      | Overview of all tables with row counts, column counts, FK relationships. |
| `inspect_table`    | Full structure of one table: columns, types, indexes, FKs, sample data. |
| `query`            | Run a safe, parameterized SQL query and get Markdown results.      |
| `natural_query`    | Ask a question in plain text; get generated SQL + results.         |
| `profile_database` | Data profile: distributions, NULL rates, relationships, sizes.     |
| `schema_graph`     | Mermaid ER diagram of table relationships.                         |

### Example: `query` with parameters

```json
{
  "sql": "SELECT * FROM users WHERE id = :id AND active = :active",
  "params": "{\"id\": 42, \"active\": true}"
}
```

Parameters use `:name` placeholders; pass the values as a JSON string in `params`.

### Example: `natural_query`

```text
question: "How many users are there?"
-> SELECT COUNT(*) FROM users
question: "Show me all orders"
-> SELECT * FROM orders LIMIT 100
```

How the question is translated:

- If `OPENAI_API_KEY` (or `ANTHROPIC_API_KEY`) is set, the question is sent to
  an LLM that returns a single read-only SQL statement. The result always
  passes through the safety validator before execution.
- Otherwise a built-in rules-based parser handles common English question
  shapes ("how many X", "show me X", "top N <column> in X", "X where column = value").
  It matches table names against the database's real schema.

A working example against a small sample database is in [`examples/`](examples/) together with ready-to-use configuration snippets for common MCP clients.

## MCP client configuration

### Claude Desktop (`claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "database": {
      "command": "python",
      "args": ["-m", "mcp_database_universal"],
      "env": {"DATABASE_URL": "sqlite:///C:/data/app.db"}
    }
  }
}
```

### Cursor / other CLI-based clients

```json
{
  "mcpServers": {
    "database": {
      "command": "uvx",
      "args": ["mcp-database-universal"],
      "env": {"DATABASE_URL": "sqlite:///C:/data/app.db"}
    }
  }
}
```

> **Windows note**: the async Postgres driver requires the Windows selector event loop. The package sets this policy automatically on `win32`, so no extra configuration is needed.

## Development

```bash
pip install -e ".[dev]"
pytest
```

Integration tests for PostgreSQL/MySQL use Docker Compose and are skipped automatically if the servers are unreachable:

```bash
docker compose -f tests/integration/docker-compose.yml up -d
pytest
```

## Safety model

- The server is **read-only by default**; `INSERT`/`UPDATE`/`DELETE`/`DROP`/`ALTER` and other write statements are blocked.
- Writes are only possible when the operator explicitly sets `DATABASE_READ_ONLY=false` **and** `DATABASE_WRITE_ENABLED=true`.
- Query results are capped by row count, timeout, and output size — runaway queries are prevented.

## License

MIT