A lightweight, extensible, cross-database MCP server for database introspection
Project description
db-inspector-mcp
A lightweight, extensible, cross-database MCP server (Model Context Protocol server) written in Python, designed to help AI coding assistants (e.g., Cursor, Claude Code, and other MCP-compatible clients) introspect, analyze, and verify SQL-based database systems.
Features
- Database Schema Discovery: List tables and views with their definitions
- Query Inspection: Analyze query structure, columns, and metadata
- Query Performance Measurement: Measure execution time and row counts
- Execution Plan Retrieval: Get database-native execution plans
- Data Sanity Checks: Compare queries, validate aggregates, and spot-check data
- Multi-Database Support: Connect to multiple databases simultaneously (SQL Server, PostgreSQL, Access)
- Cross-Database Comparison: Compare queries across different database systems for migration validation
- Read-Only by Default: Designed for safe introspection with explicit permission controls
- Security Guardrails: SQL validation prevents write operations
Prerequisites
- Python: 3.10 or higher
- Database Drivers:
- SQL Server: ODBC Driver 17 (or later) for SQL Server. Download from Microsoft
- PostgreSQL: No additional driver needed (uses
psycopg2-binary) - Microsoft Access: Microsoft Access Database Engine (ACE) - usually pre-installed on Windows, or download from Microsoft
- 32-bit Access compatibility: If you need to connect to 32-bit versions of Microsoft Access, you must install a 32-bit version of Python so that the ODBC drivers are compatible. Note that some databases like PostgreSQL may not have 32-bit ODBC drivers available.
Getting Started
The quickest way to get running is with uvx (the tool runner from uv). No cloning or virtual environments needed.
1. Install uv
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
2. Register the MCP server
Add the server entry to your MCP client config. Both Cursor and Claude Code use the same mcpServers format, just in different files:
| Client | Project-level config | User-level (global) config |
|---|---|---|
| Cursor | .cursor/mcp.json |
~/.cursor/mcp.json |
| Claude Code | .mcp.json |
~/.claude.json |
Add this to the appropriate config file:
{
"mcpServers": {
"db-inspector-mcp": {
"command": "uvx",
"args": ["--upgrade", "db-inspector-mcp"]
}
}
}
The --upgrade flag ensures uvx always pulls the latest version from PyPI instead of using a cached copy.
Alternative for Claude Code -- you can use the CLI instead of editing JSON:
claude mcp add db-inspector-mcp -- uvx --upgrade db-inspector-mcp
Shortcut -- the built-in init command registers the server globally and creates a .env template in one step:
uvx db-inspector-mcp init
3. Configure your database connection
Create a .env file in your project root (or edit the one created by init):
# SQL Server
DB_MCP_DATABASE=sqlserver
DB_MCP_CONNECTION_STRING=Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=mydb;UID=user;PWD=password
# PostgreSQL
DB_MCP_DATABASE=postgres
DB_MCP_CONNECTION_STRING=dbname=mydb user=postgres password=secret host=localhost port=5432
# Microsoft Access (ODBC -- works without Access installed)
DB_MCP_DATABASE=access_odbc
DB_MCP_CONNECTION_STRING=Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\path\to\database.accdb;
# Microsoft Access (COM -- query-by-name, requires Access installed)
DB_MCP_DATABASE=access_com
DB_MCP_CONNECTION_STRING=Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\path\to\database.accdb;
See Configuration for full details on connection strings, multi-database setups, and all environment variables.
4. Restart your client
Close and reopen Cursor or Claude Code. The MCP server will be detected and loaded automatically.
5. Try it out
Ask the AI assistant to use the database tools:
"What tables are in the database? Use db_list_tables"
"How many rows are in the users table? Use db_count_query_results"
"Verify the database is read-only using db_check_readonly_status"
Configuration
All configuration is done through environment variables, typically in a .env file in your project root. The server loads .env automatically at startup.
Environment Variables
| Variable | Description | Default | Required |
|---|---|---|---|
DB_MCP_DATABASE |
Database type: sqlserver, postgres, access_odbc, or access_com |
- | Yes* |
DB_MCP_CONNECTION_STRING |
Database connection string | - | Yes* |
DB_MCP_<name>_DATABASE |
Database type for named database (multi-database) | - | Yes* |
DB_MCP_<name>_CONNECTION_STRING |
Connection string for named database (multi-database) | - | Yes* |
DB_MCP_PROJECT_DIR |
Project directory for .env file lookup (see User-Level Configuration) |
auto-detected | No |
DB_MCP_QUERY_TIMEOUT_SECONDS |
Query timeout in seconds | 30 |
No |
DB_MCP_ALLOW_DATA_ACCESS |
Global flag to enable data access tools | false |
No |
DB_MCP_ALLOW_PREVIEW |
Per-tool override for db_preview |
false |
No |
DB_MCP_VERIFY_READONLY |
Verify read-only at startup | true |
No |
DB_MCP_READONLY_FAIL_ON_WRITE |
Fail startup if write permissions detected | false |
No |
*Either single-database (DB_MCP_DATABASE + DB_MCP_CONNECTION_STRING) or multi-database (DB_MCP_<name>_DATABASE + DB_MCP_<name>_CONNECTION_STRING) configuration is required.
Connection Strings
SQL Server
DB_MCP_DATABASE=sqlserver
# ODBC connection string
DB_MCP_CONNECTION_STRING=Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=mydb;UID=user;PWD=password
# Or using DSN
DB_MCP_CONNECTION_STRING=DSN=MySQLServerDSN
PostgreSQL
DB_MCP_DATABASE=postgres
DB_MCP_CONNECTION_STRING=dbname=mydb user=postgres password=secret host=localhost port=5432
Microsoft Access
Two backends are available:
access_odbc-- Standard SQL queries via ODBC (works without Access installed)access_com-- Query-by-name and native SQL extraction via COM (requires Access installed)
DB_MCP_DATABASE=access_odbc # or access_com
DB_MCP_CONNECTION_STRING=Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\path\to\database.accdb;
Both backends support .accdb, .accda, and .mdb file formats. The driver name in the connection string is the same regardless of file extension.
Relative paths are resolved against the directory containing the .env file, making configurations portable:
DB_MCP_CONNECTION_STRING=Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=.\database.accdb;
# Or just the filename
DB_MCP_CONNECTION_STRING=database.accdb
Use access_odbc for standard SQL operations. Use access_com when you need to retrieve Access queries by name (see db_get_access_query_definition).
Multi-Database Configuration
Connect to multiple databases simultaneously for migration validation, testing, or comparison scenarios. Use the pattern DB_MCP_<name>_DATABASE and DB_MCP_<name>_CONNECTION_STRING:
# Migration scenario: Access to SQL Server
DB_MCP_LEGACY_DATABASE=access_com
DB_MCP_LEGACY_CONNECTION_STRING=Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\path\to\legacy.accdb;
DB_MCP_NEW_DATABASE=sqlserver
DB_MCP_NEW_CONNECTION_STRING=Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=mydb;UID=user;PWD=password
Name databases to match your use case: legacy/new, prod/dev, v1/v2, etc. The first database configured (or one named "default") becomes the default.
When multiple databases are configured, all tools accept an optional database parameter:
db_count_query_results("SELECT * FROM customers", database="legacy")
db_compare_queries(
"SELECT * FROM customers WHERE active = 1",
"SELECT * FROM customers WHERE status = 'active'",
database1="legacy",
database2="new"
)
Call db_list_databases() first to discover available database names.
Environment Variable Precedence
- MCP server
envsection (highest priority) -- values set in the MCP config file .env.local-- personal overrides (gitignored).env-- project-specific configuration (lowest priority)
MCP Client Setup
Cursor
Project-level -- add .cursor/mcp.json to your project root (can be version-controlled for team sharing):
{
"mcpServers": {
"db-inspector-mcp": {
"command": "uvx",
"args": ["--upgrade", "db-inspector-mcp"]
}
}
}
User-level -- add to ~/.cursor/mcp.json to make the server available in all projects. The server automatically finds each project's .env file via workspace detection (see User-Level Configuration below).
Claude Code
Project-level -- add .mcp.json to your project root:
{
"mcpServers": {
"db-inspector-mcp": {
"command": "uvx",
"args": ["--upgrade", "db-inspector-mcp"]
}
}
}
User-level -- add to ~/.claude.json to make the server available in all projects.
CLI alternative -- register without editing JSON:
claude mcp add db-inspector-mcp -- uvx --upgrade db-inspector-mcp
Other MCP Clients
Any MCP-compatible client can use this server. The configuration format is the same mcpServers object shown above -- consult your client's documentation for where to place it.
User-Level Configuration
When configured at the user level (global config), you don't need a per-project MCP config file. The server finds each project's .env file automatically:
- At startup -- searches upward from the working directory for
.env,.cursor/mcp.json, orpyproject.toml - On first tool call -- if no
.envwas found at startup, asks the client for its workspace roots via the MCP protocol
This works even when the working directory is not the project root (the typical case for user-level configs).
Fallback: If automatic detection doesn't work, set DB_MCP_PROJECT_DIR explicitly in your MCP config:
{
"mcpServers": {
"db-inspector-mcp": {
"command": "uvx",
"args": ["--upgrade", "db-inspector-mcp"],
"env": {
"DB_MCP_PROJECT_DIR": "C:\\Users\\me\\projects\\my-project"
}
}
}
}
Development Install
For contributing or running from source, see CONTRIBUTING.md. The short version:
git clone https://github.com/joyfullservice/db-inspector-mcp.git
cd db-inspector-mcp
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # macOS/Linux
pip install -e ".[dev]"
For development installs, use python -m db_inspector_mcp.main as the command in your MCP config:
{
"mcpServers": {
"db-inspector-mcp": {
"command": "python",
"args": ["-m", "db_inspector_mcp.main"]
}
}
}
Troubleshooting
If the MCP server doesn't load:
-
Check MCP logs -- In Cursor, open the Command Palette (
Ctrl+Shift+P/Cmd+Shift+P) and look for MCP-related output. In Claude Code, check the terminal output. -
Verify the command works -- run
uvx db-inspector-mcp --helpin your terminal. -
Test the connection manually:
DB_MCP_DATABASE=sqlserver DB_MCP_CONNECTION_STRING="your-connection-string" uvx db-inspector-mcp
-
Check your
.envfile -- make sure it's in the project root, the connection string format matches your database type, and there are no syntax errors.
Available Tools
Database Management
db_list_databases()
List all configured database backends.
db_list_databases()
# Returns: {"databases": [{"name": "source", "is_default": True}, {"name": "dest", "is_default": False}], "default": "source"}
Query Analysis Tools
db_count_query_results(query, database=None)
Count rows a SELECT query returns by wrapping it in SELECT COUNT(*) FROM (your_query).
db_count_query_results("SELECT * FROM users WHERE active = 1")
# Returns: {"count": 1234}
db_get_query_columns(query, database=None)
Analyze column schema of a query's results (fetches 0 rows, inspects metadata only).
db_get_query_columns("SELECT * FROM users")
# Returns: {"columns": [{"name": "id", "type": "int", "nullable": false, ...}, ...]}
db_sum_query_column(query, column, database=None)
Sum a specific column from a query's results.
db_sum_query_column("SELECT amount FROM transactions", "amount")
# Returns: {"sum": 12345.67}
db_measure_query(sql, max_rows=1000, database=None)
Return execution time, row count, and whether the row cap was hit.
db_measure_query("SELECT * FROM large_table", max_rows=1000)
# Returns: {"execution_time_ms": 123.45, "row_count": 1000, "hit_limit": true}
db_preview(sql, max_rows=100, database=None)
Sample N rows from a query result. Requires DB_MCP_ALLOW_DATA_ACCESS=true or DB_MCP_ALLOW_PREVIEW=true.
db_preview("SELECT * FROM users ORDER BY created_at DESC", max_rows=10)
# Returns: {"rows": [{"id": 1, "name": "Alice", ...}, ...]}
db_explain(sql, database=None)
Return database-native execution plan.
db_explain("SELECT * FROM users JOIN orders ON users.id = orders.user_id")
# Returns: {"plan": "<execution plan XML/JSON>"}
Comparison Tool
db_compare_queries(sql1, sql2, compare_samples=False, database1=None, database2=None)
Compare two queries side-by-side, optionally from different databases. Useful for migration validation.
If compare_samples=True, requires data access permission.
db_compare_queries(
"SELECT * FROM customers WHERE active = 1",
"SELECT * FROM customers WHERE status = 'active'",
database1="legacy",
database2="new",
compare_samples=True
)
# Returns: {"row_count_diff": 0, "columns_missing_in_2": [], "type_mismatches": [], ...}
Schema Introspection Tools
db_list_tables(database=None)
List all tables in the database with metadata.
db_list_tables()
# Returns: {"tables": [{"name": "users", "schema": "dbo", "row_count": 1234}, ...]}
db_list_views(database=None)
List all views with their SQL definitions.
db_list_views()
# Returns: {"views": [{"name": "active_users", "schema": "dbo", "definition": "SELECT ..."}, ...]}
Note for Access COM backend: Returns query names without SQL (extraction is expensive). Use db_get_access_query_definition() to get SQL for specific queries.
db_get_access_query_definition(name, database=None)
Get Access query SQL definition by name. Requires the access_com backend.
db_get_access_query_definition("ActiveCustomers", database="legacy")
# Returns: {"name": "ActiveCustomers", "sql": "SELECT * FROM Customers WHERE Active = True", "type": "Select"}
Security Tool
db_check_readonly_status(database=None)
Verify that the database connection is read-only.
db_check_readonly_status()
# Returns: {"readonly": true, "details": "Read-only verification passed"}
Security Model
Read-Only by Default
All SQL queries are validated to reject write operations (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, etc.).
Data Access Permissions
Some tools require explicit authorization:
db_preview: RequiresDB_MCP_ALLOW_DATA_ACCESS=trueorDB_MCP_ALLOW_PREVIEW=truedb_compare_querieswithcompare_samples=True: Requires data access permission
Metadata tools (row counts, column schemas, execution plans) are always available.
Data Access Considerations
By default, db-inspector-mcp exposes only schema metadata and aggregates — table names, column types, row counts, and execution plans. No actual row data leaves your database.
When you enable data access (DB_MCP_ALLOW_DATA_ACCESS=true), tools like db_preview return actual row values from your database. This data is sent to your AI provider as part of the conversation context. Depending on your provider and configuration, this data may be:
- Retained in conversation logs or audit trails
- Used for model training, potentially surfacing in future model outputs
- Stored in regions that may not align with your data residency requirements
Before enabling data access on databases that contain personally identifiable information (PII), protected health information (PHI), financial records, or other regulated data, verify your AI provider's data retention and model training policies. Most providers offer settings to opt out of training — ensure these are configured appropriately for your environment.
For granular control, use per-connection overrides to enable data access selectively — for example, allowing it on development databases while keeping it off for production:
DB_MCP_DEV_ALLOW_DATA_ACCESS=true
DB_MCP_PROD_ALLOW_DATA_ACCESS=false
Read-Only Verification
At startup (if DB_MCP_VERIFY_READONLY=true), the server verifies the database connection is read-only by checking role membership (SQL Server) or privileges (PostgreSQL). If write permissions are detected, a warning is logged. Set DB_MCP_READONLY_FAIL_ON_WRITE=true to exit on detection instead.
CLI Commands
db-inspector-mcp
Starts the MCP server (stdio transport). This is how MCP clients launch it.
db-inspector-mcp init
Initialize db-inspector-mcp in a project directory:
- Creates a
.envfile from the configuration template (use--forceto overwrite) - Registers the server in
~/.cursor/mcp.jsonand~/.claude.jsonfor automatic discovery
db-inspector-mcp init # current directory
db-inspector-mcp init --force # overwrite existing .env
db-inspector-mcp init --dir /path/to/project
db-inspector-mcp --version
Show the installed version number.
db-inspector-mcp --help
Show available commands.
Development
For development setup, testing, project structure, and contribution guidelines, see CONTRIBUTING.md.
For architectural decisions and design rationale, see DECISIONS.md.
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please open an issue or submit a pull request. See CONTRIBUTING.md for development setup, testing, and adding new backends.
Planned Enhancements
- MySQL / MariaDB backend support
- SQLite backend support
- Schema resources (list tables, views, indexes) as MCP Resources
- Query linting / formatting
- Caching layer for performance
- Index recommendation assistant
- Access migration helpers
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file db_inspector_mcp-0.2.0.tar.gz.
File metadata
- Download URL: db_inspector_mcp-0.2.0.tar.gz
- Upload date:
- Size: 89.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
058a16a989a96dd5f93fa4b17774bda50e0e78552d50d518b5cddff0e6f55613
|
|
| MD5 |
e4f7746e92014e26208bc4d4617d1577
|
|
| BLAKE2b-256 |
b9cfc1cc7975c3d96796b5e0314ed5aaf1fffe12849df88537c7f45dab727b1c
|
Provenance
The following attestation bundles were made for db_inspector_mcp-0.2.0.tar.gz:
Publisher:
publish.yml on joyfullservice/db-inspector-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
db_inspector_mcp-0.2.0.tar.gz -
Subject digest:
058a16a989a96dd5f93fa4b17774bda50e0e78552d50d518b5cddff0e6f55613 - Sigstore transparency entry: 1044585280
- Sigstore integration time:
-
Permalink:
joyfullservice/db-inspector-mcp@f0141e22c6527d9549dc208ae31fbb3298df790e -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/joyfullservice
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0141e22c6527d9549dc208ae31fbb3298df790e -
Trigger Event:
release
-
Statement type:
File details
Details for the file db_inspector_mcp-0.2.0-py3-none-any.whl.
File metadata
- Download URL: db_inspector_mcp-0.2.0-py3-none-any.whl
- Upload date:
- Size: 73.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a2479036b9de11d6e262bf58b6a4781d564b52fdabbccef0087ce8bee7e4f33
|
|
| MD5 |
507104f3e6cbdb4d7fd770d59ecbc2af
|
|
| BLAKE2b-256 |
6e2f5218dfd2b4bdc47a3520bdb9051baab3e0885782b361308da53a313fcc0f
|
Provenance
The following attestation bundles were made for db_inspector_mcp-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on joyfullservice/db-inspector-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
db_inspector_mcp-0.2.0-py3-none-any.whl -
Subject digest:
9a2479036b9de11d6e262bf58b6a4781d564b52fdabbccef0087ce8bee7e4f33 - Sigstore transparency entry: 1044585326
- Sigstore integration time:
-
Permalink:
joyfullservice/db-inspector-mcp@f0141e22c6527d9549dc208ae31fbb3298df790e -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/joyfullservice
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0141e22c6527d9549dc208ae31fbb3298df790e -
Trigger Event:
release
-
Statement type: