Skip to main content

Natural Language Database Queries

Transform plain English questions into optimized SQL queries. Ask about your data naturally and let AI handle the complexity.

Intelligent Index Tuning

Automated index recommendations using enterprise-grade algorithms (Microsoft SQL Server DTA). Optimize performance without manual analysis.

Overview

The PostgreSQL MCP Server transforms database management into a natural conversation. Instead of writing complex SQL queries, analyzing execution plans, or manually tuning indexes, you simply describe what you need in plain English. The server intelligently translates your requests into optimized database operations. Perfect for:
  • Data analysts who want instant answers without writing SQL
  • Developers optimizing application performance
  • Database administrators monitoring system health
  • Teams wanting to democratize database access safely
Core capabilities:
  • Schema Intelligence: Explore database structure through natural language
  • Safe SQL Execution: Read-only mode protects production data
  • Query Optimization: Get execution plans with hypothetical index simulation
  • Performance Tuning: Industrial-strength index recommendations (DTA algorithm)
  • Health Monitoring: Comprehensive checks for indexes, connections, vacuum, replication, and more
This server supports both managed PostgreSQL services (Supabase, Neon, AWS RDS) and self-hosted instances. All operations are performed through secure database connections.

Quick Start

1

Set Up PostgreSQL Access

Get your database connection details. For managed services like Supabase or Neon, find the connection string in your dashboard. For self-hosted databases, ensure you have the host, port, database name, username, and password.
Recommended: Create a read-only database user for Studio integration to protect against accidental data modifications.
2

Add Server to NimbleBrain Studio

  1. Open NimbleBrain Studio
  2. Navigate to the MCP Servers page
  3. Search for “PostgreSQL MCP Server”
  4. Click “Add to Workspace”
  5. In the environment variables, add:
    • DATABASE_URI: Your full connection string (e.g., postgresql://user:password@host:port/database)
  6. For production use, set --access-mode restricted to enable read-only safety features
3

Test Your Connection

Open a playbook and try:“Show me all the schemas in my database”The server will list your database schemas. Then try:“What tables are in the public schema?”You should see a list of all tables. Now you’re ready to query your database with natural language!

Available Tools

Lists all schemas in your PostgreSQL database with their ownership and classification (system vs user schemas).What it does:
  • Retrieves all schemas from information_schema.schemata
  • Classifies schemas as System, System Information, or User schemas
  • Shows schema owners for permission auditing
  • Ordered by type and name for easy navigation
Parameters: None - simply lists all schemasReturns: Array of schema objects with:
  • schema_name: Name of the schema
  • schema_owner: Owner of the schema
  • schema_type: Classification (System Schema, System Information Schema, or User Schema)
Natural language examples:
  • “What schemas exist in my database?”
  • “Show me all the database schemas”
  • “List the user-created schemas”
  • “Which schemas are system schemas?”
Example response:
[
  {"schema_name": "public", "schema_owner": "postgres", "schema_type": "User Schema"},
  {"schema_name": "auth", "schema_owner": "supabase_admin", "schema_type": "User Schema"},
  {"schema_name": "pg_catalog", "schema_owner": "postgres", "schema_type": "System Schema"}
]
Use this as your first step when exploring an unfamiliar database. It provides a high-level map of the database structure.
Lists database objects within a specific schema, including tables, views, sequences, and extensions.What it does:
  • Queries information_schema tables for object metadata
  • Filters by schema and object type
  • Returns structured information about each object
  • Supports tables, views, sequences, and extensions
Parameters:
ParameterTypeRequiredDefaultDescription
schema_namestringYes-Schema to query (e.g., “public”, “auth”)
object_typestringNo”table”Type of object: “table”, “view”, “sequence”, or “extension”
Returns: Array of objects with properties depending on type:
  • Tables/Views: schema, name, type
  • Sequences: schema, name, data_type
  • Extensions: name, version, relocatable
Natural language examples:
  • “What tables are in the public schema?”
  • “Show me all views in the analytics schema”
  • “List sequences in the public schema”
  • “What extensions are installed?”
Example - Tables:
[
  {"schema": "public", "name": "users", "type": "BASE TABLE"},
  {"schema": "public", "name": "orders", "type": "BASE TABLE"},
  {"schema": "public", "name": "products", "type": "BASE TABLE"}
]
Example - Extensions:
[
  {"name": "pg_stat_statements", "version": "1.10", "relocatable": false},
  {"name": "hypopg", "version": "1.4.0", "relocatable": true}
]
Use object_type="extension" to verify that required extensions like pg_stat_statements and hypopg are installed for advanced features.
Retrieves detailed information about a specific database object, including columns, constraints, indexes, and more.What it does:
  • Gets complete structure of tables and views
  • Shows all columns with data types, nullability, and defaults
  • Lists constraints (primary keys, foreign keys, unique, check)
  • Displays all indexes with their definitions
  • Provides sequence and extension details
Parameters:
ParameterTypeRequiredDefaultDescription
schema_namestringYes-Schema containing the object
object_namestringYes-Name of the object to inspect
object_typestringNo”table”Type: “table”, “view”, “sequence”, or “extension”
Returns: Detailed object structure with:
  • Tables/Views: basic info, columns array, constraints array, indexes array
  • Sequences: schema, name, data_type, start_value, increment
  • Extensions: name, version, relocatable status
Natural language examples:
  • “Show me the structure of the users table”
  • “What columns does the orders table have?”
  • “What indexes exist on the products table?”
  • “Show me all constraints on the accounts table”
Example - Table details:
{
  "basic": {"schema": "public", "name": "users", "type": "table"},
  "columns": [
    {"column": "id", "data_type": "integer", "is_nullable": "NO", "default": "nextval('users_id_seq'::regclass)"},
    {"column": "email", "data_type": "character varying", "is_nullable": "NO", "default": null},
    {"column": "created_at", "data_type": "timestamp", "is_nullable": "YES", "default": "now()"}
  ],
  "constraints": [
    {"name": "users_pkey", "type": "PRIMARY KEY", "columns": ["id"]},
    {"name": "users_email_key", "type": "UNIQUE", "columns": ["email"]}
  ],
  "indexes": [
    {"name": "users_pkey", "definition": "CREATE UNIQUE INDEX users_pkey ON public.users USING btree (id)"},
    {"name": "users_email_idx", "definition": "CREATE INDEX users_email_idx ON public.users USING btree (email)"}
  ]
}
This tool is essential before running complex queries. Understanding table structure helps AI generate more accurate SQL.
Executes SQL queries against your PostgreSQL database. Supports both unrestricted and read-only (restricted) modes.What it does:
  • Executes any SQL statement in unrestricted mode
  • Enforces read-only operations in restricted mode
  • Returns query results as structured data
  • Provides timeout protection (30s in restricted mode)
  • Prevents destructive operations in production
Parameters:
ParameterTypeRequiredDefaultDescription
sqlstringYes-SQL query to execute
Access Modes:
  • Unrestricted (Development): Allows all SQL operations including INSERT, UPDATE, DELETE, DROP
  • Restricted (Production): Only allows SELECT queries, enforces 30-second timeout, blocks destructive operations
Natural language examples:
  • “Show me the first 10 users”
  • “Count how many orders were placed today”
  • “Find all products with price greater than 100”
  • “Get the average order value by month”
Example query:
SELECT id, email, created_at
FROM users
WHERE created_at > NOW() - INTERVAL '7 days'
ORDER BY created_at DESC
LIMIT 10
Example response:
[
  {"id": 1234, "email": "[email protected]", "created_at": "2025-01-03 14:23:45"},
  {"id": 1235, "email": "[email protected]", "created_at": "2025-01-03 10:15:22"}
]
Production Safety: Always use --access-mode restricted for production databases. This prevents accidental data modifications and enforces query timeouts.
You rarely need to use this tool directly. Instead, ask questions in natural language and let AI generate optimized SQL for you.
Explains how PostgreSQL will execute a query, showing the execution plan, cost estimates, and performance characteristics. Supports hypothetical index simulation.What it does:
  • Generates execution plans with EXPLAIN
  • Shows estimated vs actual costs with ANALYZE
  • Simulates hypothetical indexes using HypoPG extension
  • Reveals sequential scans, index usage, and join strategies
  • Identifies performance bottlenecks before execution
Parameters:
ParameterTypeRequiredDefaultDescription
sqlstringYes-SQL query to explain
analyzebooleanNofalseRun query for real statistics (takes longer but more accurate)
hypothetical_indexesarrayNo[]Simulated indexes to test performance impact
Hypothetical Index Format: Each index object requires:
  • table: Table name (e.g., “users”)
  • columns: Array of column names (e.g., [“email”] or [“last_name”, “first_name”])
  • using: Optional index method (default: “btree”, options: “hash”, “gist”, “gin”, etc.)
Natural language examples:
  • “Explain how this query will run: SELECT * FROM users WHERE email = ‘[email protected]’”
  • “Show me the execution plan with analysis for my orders query”
  • “What would happen if I added an index on users.email?”
  • “Simulate an index on (last_name, first_name) and show the performance impact”
Example - Basic explain:
QUERY PLAN:
Seq Scan on users  (cost=0.00..458.00 rows=100 width=532)
  Filter: (email = '[email protected]'::text)
Example - With hypothetical index: Request:
{
  "sql": "SELECT * FROM users WHERE email = '[email protected]'",
  "hypothetical_indexes": [
    {"table": "users", "columns": ["email"], "using": "btree"}
  ]
}
Result:
QUERY PLAN (with hypothetical index):
Index Scan using <hypothetical_index> on users  (cost=0.29..8.31 rows=1 width=532)
  Index Cond: (email = '[email protected]'::text)

Cost reduced from 458.00 to 8.31 (98% improvement)
Requires HypoPG Extension: Hypothetical indexes need the hypopg extension installed. The tool will notify you if it’s missing.
Use analyze=false (default) for quick estimates without query execution. Use analyze=true only when you need precise actual statistics.
Identifies the slowest and most resource-intensive queries using PostgreSQL’s pg_stat_statements extension.What it does:
  • Analyzes query statistics from pg_stat_statements
  • Ranks queries by total time, mean time, or resource consumption
  • Shows execution counts, average time, and resource usage
  • Identifies queries that would benefit most from optimization
  • Provides normalized query text (parameters replaced)
Parameters:
ParameterTypeRequiredDefaultDescription
sort_bystringNo”resources”Ranking criteria: “total_time”, “mean_time”, or “resources”
limitintegerNo10Number of queries to return (for total_time/mean_time)
Sort Options:
  • “resources”: Comprehensive resource analysis (CPU, I/O, memory, calls)
  • “total_time”: Queries with highest cumulative execution time
  • “mean_time”: Queries with highest average execution time per call
Natural language examples:
  • “What are my slowest queries?”
  • “Show me the most resource-intensive database operations”
  • “Which queries have the highest average execution time?”
  • “Find queries that run most frequently”
Example response (resources mode):
Top Resource-Intensive Queries:

1. Query: SELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE o.created_at > $1
   Calls: 45,234
   Total Time: 1,234.56 ms
   Mean Time: 27.31 ms
   Rows Retrieved: 2,145,678

2. Query: SELECT COUNT(*) FROM products WHERE category = $1 AND price > $2
   Calls: 12,456
   Total Time: 892.34 ms
   Mean Time: 71.64 ms
   Rows Retrieved: 124,560
Requires pg_stat_statements Extension: This tool depends on the pg_stat_statements extension being installed and enabled in your PostgreSQL configuration.
Use “resources” mode (default) for general optimization. It balances execution time, frequency, and resource usage to find the most impactful optimization opportunities.
Analyzes your database workload and recommends optimal indexes using industrial-strength algorithms from Microsoft SQL Server.What it does:
  • Examines frequently executed queries from pg_stat_statements
  • Applies Microsoft SQL Server DTA (Database Tuning Advisor) algorithm
  • Recommends indexes that provide maximum performance improvement
  • Considers index size limits and resource constraints
  • Provides CREATE INDEX statements ready to execute
  • Alternative LLM-based optimization available
Parameters:
ParameterTypeRequiredDefaultDescription
max_index_size_mbintegerNo10000Maximum size for recommended indexes (in MB)
methodstringNo”dta”Analysis method: “dta” or “llm”
Analysis Methods:
  • “dta”: Microsoft SQL Server Database Tuning Advisor algorithm - proven, deterministic, production-ready
  • “llm”: AI-powered optimization - experimental, considers broader context
Natural language examples:
  • “Analyze my database and recommend indexes”
  • “What indexes would improve my query performance?”
  • “Optimize my database for better speed”
  • “Find the best indexes for my workload”
Example response:
Workload Analysis Complete
Analyzed: 45 unique queries from pg_stat_statements

Recommended Indexes (5):

1. CREATE INDEX idx_users_email ON users (email);
   Estimated Impact: 87% faster queries
   Affected Queries: 12
   Size: 45 MB

2. CREATE INDEX idx_orders_user_created ON orders (user_id, created_at);
   Estimated Impact: 92% faster queries
   Affected Queries: 8
   Size: 128 MB

3. CREATE INDEX idx_products_category_price ON products (category, price);
   Estimated Impact: 76% faster queries
   Affected Queries: 6
   Size: 67 MB

Total Storage Required: 240 MB
Estimated Overall Performance Improvement: 73%
The DTA algorithm is the same technology used in Microsoft SQL Server’s query optimization. It has been proven in enterprise production environments.
Run this analysis during low-traffic periods. It examines historical query patterns, so more execution history provides better recommendations.
Analyzes specific SQL queries (up to 10) and recommends optimal indexes tailored to those queries.What it does:
  • Analyzes provided queries instead of workload history
  • Applies DTA algorithm or LLM optimization
  • Recommends indexes optimized for specific query patterns
  • Perfect for optimizing new features before deployment
  • Simulates index impact on query execution plans
Parameters:
ParameterTypeRequiredDefaultDescription
queriesarrayYes-List of SQL queries to analyze (1-10 queries)
max_index_size_mbintegerNo10000Maximum size for recommended indexes (in MB)
methodstringNo”dta”Analysis method: “dta” or “llm”
Natural language examples:
  • “Optimize these queries: [query list]”
  • “What indexes would help this specific query?”
  • “I have 3 slow queries, recommend indexes for them”
  • “Analyze these queries and suggest performance improvements”
Example request:
{
  "queries": [
    "SELECT * FROM users WHERE email = $1",
    "SELECT * FROM orders WHERE user_id = $1 AND created_at > $2",
    "SELECT COUNT(*) FROM products WHERE category = $1 AND price > $2"
  ],
  "max_index_size_mb": 5000,
  "method": "dta"
}
Example response:
Query-Specific Index Recommendations

For Query 1: SELECT * FROM users WHERE email = $1
Recommendation: CREATE INDEX idx_users_email ON users (email);
Impact: Sequential scan → Index scan (98.2% faster)

For Query 2: SELECT * FROM orders WHERE user_id = $1 AND created_at > $2
Recommendation: CREATE INDEX idx_orders_user_created ON orders (user_id, created_at);
Impact: 345ms → 12ms (96.5% faster)

For Query 3: SELECT COUNT(*) FROM products WHERE category = $1 AND price > $2
Recommendation: CREATE INDEX idx_products_cat_price ON products (category, price);
Impact: Full table scan → Index-only scan (94.1% faster)

Total Storage: 156 MB
Overall Performance Gain: 96.3%
Limited to 10 queries per analysis. For larger workloads, use analyze_workload_indexes instead.
Use this before deploying new features. Analyze your new queries to proactively add optimal indexes.
Performs comprehensive health checks on your PostgreSQL database, identifying potential issues before they become problems.What it does:
  • Checks index health (invalid, duplicate, bloated indexes)
  • Monitors connection utilization and connection pool status
  • Analyzes vacuum health and transaction ID wraparound risk
  • Validates sequences approaching maximum values
  • Checks replication lag and replication slot health
  • Measures buffer cache hit rates for tables and indexes
  • Identifies invalid constraints
Parameters:
ParameterTypeRequiredDefaultDescription
health_typestringNo”all”Health check types (comma-separated or “all”)
Health Check Types:
  • “index”: Invalid, duplicate, and bloated indexes
  • “connection”: Connection count and utilization
  • “vacuum”: Vacuum health and transaction wraparound risk
  • “sequence”: Sequences near maximum values
  • “replication”: Replication lag and slot health
  • “buffer”: Buffer cache hit rates
  • “constraint”: Invalid constraints
  • “all”: Runs all checks (default)
Natural language examples:
  • “Check my database health”
  • “Are there any problems with my database?”
  • “Check index health”
  • “Monitor connection utilization”
  • “Is my database at risk of transaction ID wraparound?”
Example response:
Database Health Report

✅ INDEX HEALTH
- Valid indexes: 47
- Invalid indexes: 1 (users_email_idx - needs rebuild)
- Duplicate indexes: 2 (consider removing)
- Bloated indexes: 3 (total waste: 456 MB)

✅ CONNECTION HEALTH
- Active connections: 45 / 100 (45%)
- Idle connections: 12
- Status: Healthy

⚠️ VACUUM HEALTH
- Last autovacuum: 3 days ago
- Transaction ID age: 1.2B (58% to wraparound)
- Recommendation: Schedule manual VACUUM soon

✅ BUFFER CACHE
- Table hit rate: 99.2% (Excellent)
- Index hit rate: 98.7% (Excellent)

⚠️ REPLICATION
- Replication lag: 234ms (Moderate)
- Replication slots: 2 active
- Status: Monitor closely

Overall Status: Healthy with 2 warnings
Run health checks regularly (daily or weekly) to catch issues early. Set up automated alerts for critical problems.
Use specific health types during incident response. For example, health_type="connection" when investigating connection pool issues.

Authentication & Configuration

Connection Configuration

The PostgreSQL MCP Server requires database credentials to establish connections. You can provide connection information in two ways: Option 1: Connection URI (Recommended)
postgresql://username:password@hostname:port/database
Option 2: Individual Parameters Configure in Studio environment variables:
  • PGHOST: Database hostname
  • PGPORT: Port number (default: 5432)
  • PGDATABASE: Database name
  • PGUSER: Username
  • PGPASSWORD: Password
Access Modes The server supports two operational modes:
  • Restricted Mode (Production)
  • Unrestricted Mode (Development)
Recommended for production environmentsEnable with: --access-mode restrictedFeatures:
  • ✅ Read-only SQL execution (SELECT only)
  • ✅ 30-second query timeout
  • ✅ Blocks destructive operations (DROP, DELETE, UPDATE)
  • ✅ Safe for production data
  • ✅ All analysis tools available
Perfect for:
  • Production database analysis
  • Data exploration by non-DBAs
  • Reporting and analytics
  • AI-powered data queries

Managed PostgreSQL Services

The server works seamlessly with popular managed PostgreSQL providers:
Connection Setup:
  1. Log in to your Supabase dashboard
  2. Navigate to Project Settings → Database
  3. Find “Connection String” section
  4. Copy the URI (Direct connection recommended for MCP)
  5. Replace [YOUR-PASSWORD] with your database password
Example URI:
postgresql://postgres:[YOUR-PASSWORD]@db.xxxxxxxxxxxx.supabase.co:5432/postgres
Required Extensions: Supabase includes pg_stat_statements by default. For index optimization:
CREATE EXTENSION IF NOT EXISTS hypopg;
Use Supabase’s connection pooler for better performance with multiple Studio users.
Connection Setup:
  1. Open your Neon console
  2. Select your project and branch
  3. Go to Dashboard → Connection Details
  4. Copy the connection string
Example URI:
postgresql://username:[email protected]/neondb
Features:
  • ✅ Instant branching for safe testing
  • ✅ Auto-scaling based on usage
  • ✅ Built-in connection pooling
Neon’s branching feature is perfect for testing index recommendations before applying to production.
Connection Setup:
  1. Open AWS RDS Console
  2. Select your PostgreSQL instance
  3. Find “Connectivity & security” section
  4. Copy the endpoint URL
  5. Construct connection string
Example URI:
postgresql://username:[email protected]:5432/postgres
Enable Extensions:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS hypopg;
Security:
  • Configure security groups to allow Studio IP addresses
  • Use IAM database authentication for enhanced security
  • Enable SSL/TLS connections
Connection Setup:
  1. Open Cloud SQL Console
  2. Select your PostgreSQL instance
  3. Navigate to Connections
  4. Get public IP address or use Cloud SQL Proxy
  5. Construct connection string
Example URI:
postgresql://username:[email protected]:5432/postgres
Recommended: Use Cloud SQL Proxy for secure connections without exposing public IPs.
Connection Setup:
  1. Open DigitalOcean Control Panel
  2. Navigate to Databases
  3. Select your PostgreSQL cluster
  4. Go to Connection Details
  5. Copy the connection string (sslmode=require included)
Example URI:
postgresql://username:[email protected]:25060/defaultdb?sslmode=require
Connection Setup:
  1. Open Azure Portal
  2. Navigate to your PostgreSQL server
  3. Select Connection strings under Settings
  4. Copy the connection string
Example URI:
postgresql://username@servername:[email protected]:5432/postgres?sslmode=require
Note: Azure requires @servername suffix in username.

Self-Hosted PostgreSQL

Default Connection:
postgresql://postgres:password@localhost:5432/postgres
Install Required Extensions:
-- Enable query statistics
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- Enable hypothetical index simulation
CREATE EXTENSION IF NOT EXISTS hypopg;
Configure pg_stat_statements: Edit postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.track = all
Restart PostgreSQL after configuration changes.
Quick Start:
docker run -d \
  --name postgres-mcp \
  -e POSTGRES_PASSWORD=yourpassword \
  -e POSTGRES_DB=mydb \
  -p 5432:5432 \
  postgres:16
Connection URI:
postgresql://postgres:yourpassword@localhost:5432/mydb
Enable Extensions:
docker exec -it postgres-mcp psql -U postgres -d mydb
Then run:
CREATE EXTENSION pg_stat_statements;
CREATE EXTENSION hypopg;
Firewall Configuration:Allow PostgreSQL port (default 5432):
# Ubuntu/Debian
sudo ufw allow 5432/tcp

# CentOS/RHEL
sudo firewall-cmd --permanent --add-port=5432/tcp
sudo firewall-cmd --reload
PostgreSQL Authentication:Edit pg_hba.conf to control access:
# Allow Studio connections with password
host    all    all    0.0.0.0/0    md5
Never expose PostgreSQL directly to the internet without proper security measures. Use VPNs, SSH tunnels, or private networks.

Security Best Practices

Create Read-Only Users

For production Studio access, create dedicated read-only users:
-- Create read-only user
CREATE USER studio_reader WITH PASSWORD 'secure_password';

-- Grant read access to all tables
GRANT CONNECT ON DATABASE mydb TO studio_reader;
GRANT USAGE ON SCHEMA public TO studio_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO studio_reader;

-- Ensure future tables are readable
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO studio_reader;
Use this user with --access-mode restricted for maximum safety.

Enable SSL/TLS Encryption

Always use encrypted connections for production:Connection URI with SSL:
postgresql://user:pass@host:5432/db?sslmode=require
SSL Modes:
  • require: Encrypt connection (recommended minimum)
  • verify-ca: Encrypt and verify server certificate
  • verify-full: Encrypt, verify certificate, and hostname
Most managed services enable SSL by default.

Use Connection Pooling

For multiple users or high query volume, use connection pooling:PgBouncer Example:
postgresql://user:pass@pgbouncer-host:6432/db
Benefits:
  • Reduces connection overhead
  • Better resource utilization
  • Protects against connection exhaustion

Audit and Monitoring

Track database access with logging:Enable Query Logging:
ALTER SYSTEM SET log_statement = 'all';
ALTER SYSTEM SET log_duration = on;
SELECT pg_reload_conf();
Monitor with pg_stat_statements: Queries executed through Studio are tracked, allowing you to audit all AI-generated SQL.

Required PostgreSQL Extensions

For full functionality, install these extensions:
ExtensionRequired ForInstallation
pg_stat_statementsQuery analysis, workload optimization, top queriesCREATE EXTENSION pg_stat_statements;
hypopgHypothetical index simulation in explain plansCREATE EXTENSION hypopg;
The server will notify you if required extensions are missing when you attempt to use advanced features.

Example Workflows

  • Explore Unknown Database
  • Find Slow Queries
  • Optimize New Feature
  • Data Analysis
  • Database Health Monitoring
  • Query Troubleshooting
  • Schema Investigation
Scenario: You’ve been given access to a new database and need to understand its structure.Natural language workflow:
  1. “What schemas exist in this database?”
    • Server uses list_schemas to show all database schemas
    • Identifies user schemas vs system schemas
  2. “What tables are in the public schema?”
    • Server uses list_objects with schema_name=“public”
    • Lists all tables with their types
  3. “Show me the structure of the users table”
    • Server uses get_object_details for the users table
    • Displays columns, data types, constraints, and indexes
  4. “What are the first 10 users?”
    • Server generates: SELECT * FROM public.users LIMIT 10
    • Executes query and returns results
Result: Complete understanding of database structure without writing a single SQL query.

Troubleshooting

Problem: Server cannot connect because DATABASE_URI is not configured.Solution:
  1. Open NimbleBrain Studio
  2. Navigate to MCP Servers → PostgreSQL MCP Server
  3. Click “Configure” or “Edit”
  4. Add environment variable:
    • Key: DATABASE_URI
    • Value: Your full connection string
  5. Save and restart the server
Example connection strings:
Problem: Connection string is provided but connection fails.Common causes:
  1. Incorrect credentials
    • Verify username and password
    • Check for special characters that need URL encoding
  2. Network/Firewall blocking connection
    • Verify database server is reachable
    • Check firewall rules allow port 5432
    • For cloud databases, verify IP allowlist
  3. Wrong host or port
    • Confirm hostname is correct
    • Verify port (default: 5432)
    • Check if using connection pooler (different port)
  4. Database doesn’t exist
    • Verify database name in connection string
    • Create database if needed
  5. SSL/TLS required but not enabled
    • Add ?sslmode=require to connection string
    • Most managed services require SSL
Debug steps:
# Test connection from command line
psql "postgresql://user:pass@host:5432/db"

# Check if server is reachable
telnet hostname 5432
Problem: Advanced query analysis features require pg_stat_statements extension.Solution:For managed services:
  • Most providers include this extension by default
  • Check provider documentation for enabling extensions
For self-hosted PostgreSQL:
  1. Enable in postgresql.conf:
    shared_preload_libraries = 'pg_stat_statements'
    pg_stat_statements.track = all
    
  2. Restart PostgreSQL:
    sudo systemctl restart postgresql
    
  3. Create extension:
    CREATE EXTENSION pg_stat_statements;
    
  4. Verify installation:
    SELECT * FROM pg_stat_statements LIMIT 1;
    
Affected features without this extension:
  • get_top_queries - Cannot identify slow queries
  • analyze_workload_indexes - Cannot analyze workload patterns
Problem: Hypothetical index simulation requires hypopg extension.Solution:For managed services: Check if provider supports hypopg:
  • Supabase: ✅ Available
  • Neon: ⚠️ Check current support
  • RDS: ✅ Available (enable in parameter group)
  • Cloud SQL: ⚠️ May need to request
For self-hosted PostgreSQL:
  1. Install hypopg:
    # Ubuntu/Debian
    sudo apt-get install postgresql-16-hypopg
    
    # From source
    git clone https://github.com/HypoPG/hypopg
    cd hypopg
    make
    sudo make install
    
  2. Create extension:
    CREATE EXTENSION hypopg;
    
  3. Verify:
    SELECT * FROM hypopg_list_indexes();
    
Affected features without this extension:
  • explain_query with hypothetical_indexes parameter
  • Cannot simulate index impact before creation
You can still use all other features. Hypothetical indexes are optional for query explanation.
Problem: Query times out after 30 seconds in restricted mode.Cause: Restricted mode enforces 30-second timeout to protect production databases.Solutions:
  1. Optimize the query:
    • Use explain_query to identify bottlenecks
    • Use analyze_query_indexes to get index recommendations
    • Add recommended indexes
  2. Add appropriate indexes:
    • Long queries usually indicate missing indexes
    • Use index optimization tools
  3. Use unrestricted mode (dev only):
    • Only for non-production databases
    • Change --access-mode to unrestricted
    • No timeout enforcement
  4. Limit result set:
    • Add LIMIT clause to reduce rows returned
    • Use pagination for large datasets
    • Filter data before aggregation
Example optimization workflow:
"This query is timing out: SELECT * FROM large_table WHERE status = 'active'"
→ Server explains query, shows sequential scan
→ "What index would help?"
→ Server recommends: CREATE INDEX idx_large_table_status ON large_table(status)
→ Create index
→ Query now completes in <1 second
Problem: Permission denied when executing queries or accessing tables.Common scenarios:
  1. User lacks SELECT permissions:
    -- Grant read access to schema
    GRANT USAGE ON SCHEMA public TO your_user;
    
    -- Grant read access to all tables
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO your_user;
    
    -- Grant access to future tables
    ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT SELECT ON TABLES TO your_user;
    
  2. Trying to modify data in restricted mode:
    • Restricted mode blocks INSERT, UPDATE, DELETE, DROP
    • This is intentional for production safety
    • Use unrestricted mode only in development
  3. Row-level security (RLS) policies:
    • Some managed services (Supabase) use RLS
    • Create policies or use service role key
    • Or disable RLS for MCP user:
      ALTER TABLE your_table DISABLE ROW LEVEL SECURITY;
      
  4. Schema-level permissions:
    • Verify user has access to target schema
    • Check pg_namespace privileges
Problem: “Sorry, too many clients already” or connection pool errors.Cause: PostgreSQL has a limited number of connections (default: 100).Solutions:
  1. Use connection pooling:
    • Deploy PgBouncer or similar pooler
    • Point Studio to pooler instead of direct database
    • Pooler reuses connections efficiently
  2. Increase max_connections:
    -- Check current setting
    SHOW max_connections;
    
    -- Increase (requires restart)
    ALTER SYSTEM SET max_connections = 200;
    -- Then restart PostgreSQL
    
    Warning: More connections = more memory usage
  3. Close idle connections:
    -- Find idle connections
    SELECT pid, usename, state, state_change
    FROM pg_stat_activity
    WHERE state = 'idle'
    AND state_change < NOW() - INTERVAL '1 hour';
    
    -- Terminate specific connection
    SELECT pg_terminate_backend(pid);
    
  4. For managed services:
    • Use built-in connection pooling
    • Upgrade to plan with more connections
    • Enable connection pooler mode
Problem: analyze_workload_indexes takes a very long time or times out.Cause: DTA algorithm analyzes large query workloads and tests multiple index combinations.Solutions:
  1. Use during off-peak hours:
    • Run analysis when database is less busy
    • Schedule as weekly or monthly task
  2. Reduce max_index_size_mb:
    • Lower value = faster analysis
    • Try max_index_size_mb=1000 (1GB) instead of default 10GB
  3. Use analyze_query_indexes for specific queries:
    • Instead of analyzing entire workload
    • Target problematic queries directly
    • Faster and more focused
  4. Ensure pg_stat_statements has data:
    -- Check number of queries tracked
    SELECT COUNT(*) FROM pg_stat_statements;
    
    • If count is low, wait for more query history
    • Reset stats if they’re stale: SELECT pg_stat_statements_reset();
  5. Try LLM method for faster results:
    • Use method="llm" instead of method="dta"
    • Faster but less deterministic
    • Good for initial exploration
Problem: SSL verification fails or certificate errors.Error messages:
  • “SSL connection could not be established”
  • “certificate verify failed”
  • “self-signed certificate”
Solutions:
  1. Adjust SSL mode:
    • sslmode=require - Encrypt but don’t verify certificate
    • sslmode=verify-ca - Verify certificate authority
    • sslmode=verify-full - Full verification (most secure)
    Example:
    postgresql://user:pass@host:5432/db?sslmode=require
    
  2. For self-signed certificates:
    postgresql://user:pass@host:5432/db?sslmode=require&sslrootcert=/path/to/ca.crt
    
  3. For development (not recommended for production):
    postgresql://user:pass@host:5432/db?sslmode=disable
    
    Never disable SSL for production databases. This exposes your data to interception.
  4. For managed services:
    • Download CA certificate from provider
    • Add certificate to connection string
    • Supabase, Neon, RDS all provide CA certificates
Problem: Query returns unexpected data or wrong number of rows.Debug steps:
  1. Check the generated SQL:
    • Ask: “Show me the SQL you generated for that query”
    • Verify it matches your intent
    • Look for missing WHERE clauses or incorrect JOINs
  2. Examine table structure:
    • Use get_object_details to see column names
    • Verify data types match expectations
    • Check for unexpected NULLs
  3. Test with simple queries:
    • Start with: SELECT COUNT(*) FROM table
    • Add filters incrementally
    • Isolate the issue
  4. Check for case sensitivity:
    • PostgreSQL is case-sensitive for quoted identifiers
    • Column “Name” ≠ column “name”
    • Use lowercase for consistency
  5. Verify schema context:
    • Ensure you’re querying the right schema
    • Specify schema explicitly: schema.table
    • Use list_schemas and list_objects to confirm
When in doubt, request the exact SQL generated and review it. Natural language interpretation can sometimes miss nuances.

Learning Resources

What are indexes? Indexes are data structures that speed up data retrieval by creating quick lookup paths. Like a book’s index, they help find information without scanning every page.When to use indexes:
  • ✅ Columns in WHERE clauses
  • ✅ Columns in JOIN conditions
  • ✅ Columns in ORDER BY
  • ✅ Columns frequently searched
When NOT to use indexes:
  • ❌ Small tables (faster to scan)
  • ❌ Columns rarely queried
  • ❌ Columns with low cardinality (few unique values)
  • ❌ Tables with heavy INSERT/UPDATE (indexes slow writes)
Resources:
Understanding EXPLAIN output:Sequential Scan:
Seq Scan on users  (cost=0.00..458.00 rows=100 width=532)
  • Reads entire table
  • Slow for large tables
  • Usually means missing index
Index Scan:
Index Scan using users_email_idx on users  (cost=0.29..8.31 rows=1)
  • Uses index for fast lookup
  • Much faster than sequential scan
  • Ideal for queries with WHERE clauses
Key metrics:
  • cost: Estimated query expense (lower = faster)
  • rows: Estimated rows returned
  • width: Average row size in bytes
Resources:
Critical health indicators:1. Index Health
  • Invalid indexes don’t serve queries (need rebuild)
  • Duplicate indexes waste storage and slow writes
  • Bloated indexes need REINDEX
2. Connection Health
  • Monitor connection pool utilization
  • Watch for connection leaks
  • Tune max_connections appropriately
3. Vacuum Health
  • Prevents transaction ID wraparound
  • Reclaims storage from deleted rows
  • Critical for long-term stability
4. Buffer Cache
  • High hit rate (>95%) = good performance
  • Low hit rate = need more memory
  • Monitor with pg_stat_database
5. Replication
  • Monitor replication lag
  • Check replication slot health
  • Ensure standbys stay synchronized
Best practices:
  • Run health checks weekly
  • Set up automated alerts
  • Investigate warnings promptly
  • Document baseline metrics
Common optimization strategies:1. Use indexes effectively
  • Create indexes on filter columns
  • Use covering indexes for SELECT columns
  • Consider multi-column indexes for compound filters
2. Limit result sets
  • Use LIMIT for pagination
  • Filter early with WHERE clauses
  • Avoid SELECT * (specify columns)
3. Optimize JOINs
  • Index foreign key columns
  • Use INNER JOIN instead of subqueries when possible
  • Filter before joining when possible
4. Avoid query anti-patterns
  • ❌ SELECT * FROM large_table
  • ❌ Queries without WHERE clause on large tables
  • ❌ Functions on indexed columns: WHERE LOWER(email) = ‘x’
  • ❌ OR conditions spanning different columns
5. Use appropriate data types
  • Smaller types = better performance
  • Use INTEGER instead of BIGINT when sufficient
  • Use VARCHAR instead of TEXT for short strings
Query optimization workflow:
  1. Identify slow query with get_top_queries
  2. Analyze with explain_query
  3. Get recommendations with analyze_query_indexes
  4. Test with hypothetical indexes
  5. Create optimal indexes
  6. Verify improvement
OLTP vs OLAP workloads:OLTP (Online Transaction Processing):
  • Characteristics: Many small, fast queries
  • Examples: User login, place order, update profile
  • Optimization: B-tree indexes, primary keys, foreign keys
  • Best for: Application databases
OLAP (Online Analytical Processing):
  • Characteristics: Few large, complex queries
  • Examples: Sales reports, trend analysis, aggregations
  • Optimization: Aggregated tables, materialized views, column stores
  • Best for: Analytics, reporting
Mixed workloads:
  • Use read replicas for analytics
  • Separate OLTP and OLAP databases
  • Schedule heavy queries during off-peak
  • Use connection pooling
Optimization for Studio:
  • Studio queries are typically OLAP-style
  • Use restricted mode for production
  • Create read replicas for analytics
  • Add indexes for common query patterns
Features used by this MCP server:1. pg_stat_statements
  • Tracks query execution statistics
  • Identifies slow queries automatically
  • Foundation for workload analysis
  • Enable in all databases
2. HypoPG
  • Simulates hypothetical indexes
  • No storage overhead for testing
  • Critical for index recommendations
  • Safe to test in production
3. EXPLAIN ANALYZE
  • Shows actual vs estimated query plans
  • Identifies planner mistakes
  • Reveals actual bottlenecks
  • Use carefully (actually runs query)
4. Information Schema
  • Standard SQL metadata views
  • Database structure introspection
  • Used by all schema discovery tools
  • Always available
5. pg_stat views
  • Real-time database statistics
  • Monitor connections, locks, activity
  • Foundation for health checks
  • Essential for troubleshooting
Other powerful features:
  • Materialized views for pre-computed results
  • Partitioning for large tables
  • VACUUM and autovacuum for maintenance
  • Write-ahead logging for durability
  • Replication for high availability

Production Recommendation: Always use --access-mode restricted when connecting to production databases through Studio. This prevents accidental data modifications while maintaining full access to analysis and optimization features.