Provides read-only access to PostgreSQL databases with tools for executing SELECT queries, inspecting database schemas, viewing table structures and indexes, and tracking query history with multiple output formats (JSON, CSV, Markdown).
PostgreSQL MCP Server
A Model Context Protocol (MCP) server that provides read-only access to PostgreSQL databases. Execute SELECT queries, inspect database schema, and track query history with built-in safety features.
Features
Read-Only Query Execution: Execute SELECT queries with automatic read-only transaction enforcement
Multiple Output Formats: Results in JSON, CSV, or Markdown table format
Schema Inspection: List tables, describe table structures, view indexes, and explore schemas
Query History: Track recently executed queries with execution time and metadata
Connection Pooling: Efficient connection management with configurable pool sizes
Security: Query validation, SQL injection prevention, and read-only transaction guarantees
Database Statistics: View database size, table counts, and connection information
Installation
Clone this repository:
Install dependencies using
uv:
Configuration
Environment Variables
Create a .env file in the project root (use .env.example as a template):
Database User Setup
For security, create a dedicated read-only PostgreSQL user:
Usage
Running the Server
The server communicates via stdio and can be integrated with MCP clients like Claude Desktop.
Integrating with Claude Desktop
Add this configuration to your Claude Desktop config file:
MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
Alternatively, if using uv:
Available Tools
1. query_database
Execute SELECT queries on the database with formatted output.
Input:
Parameters:
query(required): SQL SELECT query to executeformat(optional): Output format -json(default),csv, ormarkdowntimeout(optional): Query timeout in seconds (max 300)
Output:
2. list_tables
List all tables in the database with metadata.
Input:
Parameters:
schema(optional): Filter tables by schema name
Output:
3. describe_table
Get detailed table structure including columns, types, indexes, and constraints.
Input:
Parameters:
table_name(required): Name of the tableschema(optional): Schema name (default:public)
Output:
4. list_schemas
List all schemas in the database.
Input:
Output:
5. get_table_indexes
Get all indexes for a specific table.
Input:
Parameters:
table_name(required): Name of the tableschema(optional): Schema name (default:public)
Output:
6. get_query_history
Retrieve recent query history with execution metadata.
Input:
Parameters:
limit(optional): Maximum queries to return (default: 20, max: 100)
Output:
7. get_database_stats
Get overall database statistics and metadata.
Input:
Output:
Security Features
Read-Only Enforcement
All queries are executed within read-only transactions:
Query Validation
Queries are validated before execution to prevent:
INSERT, UPDATE, DELETE operations
DROP, CREATE, ALTER operations
TRUNCATE, GRANT, REVOKE operations
Other write/admin operations
SQL Injection Prevention
Input sanitization for table and schema identifiers
Parameterized queries where applicable
Regex-based validation of identifiers
Architecture
Components
config.py: Environment configuration and validationdatabase.py: Connection pool management and read-only query executionvalidators.py: Query validation and sanitizationformatters.py: Result formatting (JSON, CSV, Markdown)history.py: Thread-safe query history trackingtools.py: MCP tool implementationsserver.py: MCP server setup and lifecycle managementtypes.py: Pydantic models for type safety
Connection Pooling
Min Size: 2 warm connections
Max Size: 10 concurrent connections
Timeout: 60 seconds command timeout, 10 seconds connection timeout
Idle Lifetime: Automatic cleanup of inactive connections
Troubleshooting
Connection Errors
Error: "Database authentication failed"
Verify
POSTGRES_USERandPOSTGRES_PASSWORDare correctCheck if the user exists in PostgreSQL
Ensure the user has CONNECT permission
Error: "Database 'myapp' not found"
Verify
POSTGRES_DATABASEmatches an existing databaseCheck database name spelling
Error: "Connection refused"
Verify PostgreSQL is running on the specified host and port
Check firewall settings
Verify
POSTGRES_HOSTandPOSTGRES_PORTare correct
Query Errors
Error: "Query contains forbidden keyword: INSERT"
This server only allows SELECT queries
Use a different tool for write operations
Error: "Table does not exist"
Verify table name and schema are correct
Use
list_tablesto see available tablesCheck if user has SELECT permission on the table
Error: "Query execution timeout"
Query took longer than the specified timeout
Optimize the query or increase timeout parameter
Check for missing indexes on large tables
Permission Errors
Error: "permission denied for table X"
The database user lacks SELECT permission
Grant appropriate permissions (see Database User Setup)
Development
Running Tests
Project Structure
License
[Add your license here]
Contributing
[Add contribution guidelines here]