Skip to main content
Glama

๐Ÿ˜ Postgres MCP Server

An AI Database Assistant, built on the Model Context Protocol

Connects an AI client to a real PostgreSQL database โ€” schema exploration, safe querying, and LLM-powered reasoning, all through MCP tools.

Python PostgreSQL SQLAlchemy Groq Docker Tests

Docker Hub ยท Architecture ยท Installation ยท Example Tool Calls


What is this?

A production-grade Model Context Protocol (MCP) server that connects an AI client (like Claude) to a real PostgreSQL database, combining direct schema/data access with LLM-powered reasoning (via Groq) for SQL generation, query explanation, optimization, and business insight generation.

Built on a fictional company database ("Orbitals Inc.") โ€” a software consultancy with employees, departments, clients, projects, orders, invoices, support tickets, and meetings โ€” to exercise realistic relational queries and multi-hop relationships.

Related MCP server: PostgreSQL MCP Server

What makes this an "AI Database Assistant," not just a SQL executor

Capability

Tool

Schema exploration

list_tables, describe_table, list_columns, search_schema

Safe, validated querying

execute_select (SELECT-only, injection-hardened, row-limited)

Relationship discovery

find_related_tables (BFS over the FK graph, direct + indirect)

AI-assisted SQL

generate_sql, explain_query, optimize_query

Business reasoning

summarize_database, business_insights (generates SQL, executes it, interprets results in plain language)

The database is the source of truth for all facts; the LLM is used for reasoning, translation, and interpretation โ€” never as a substitute for real query execution.

Architecture

MCP Layer (tools/)        โ†’ thin, declares tools only
Service Layer (services/) โ†’ business logic, orchestration
Repository Layer (repositories/) โ†’ raw SQL / SQLAlchemy queries
Database Layer (db/)      โ†’ async engine, connection pooling
LLM Client Layer (llm/)   โ†’ Groq abstraction, provider-agnostic

Each layer only knows about the one below it โ€” MCP tools never touch the database directly, and the LLM provider is swappable behind an interface (llm/base.py) without touching services.

Folder Structure

postgres-mcp-server/
โ”œโ”€โ”€ src/postgres_mcp/
โ”‚   โ”œโ”€โ”€ config.py, server.py, logging_config.py, exceptions.py
โ”‚   โ”œโ”€โ”€ db/               # async engine, session management
โ”‚   โ”œโ”€โ”€ models/            # SQLAlchemy models (11 tables)
โ”‚   โ”œโ”€โ”€ repositories/       # raw SQL against Postgres
โ”‚   โ”œโ”€โ”€ services/           # business logic
โ”‚   โ”œโ”€โ”€ llm/                # Groq provider (swappable interface)
โ”‚   โ”œโ”€โ”€ tools/               # MCP tool registration
โ”‚   โ””โ”€โ”€ utils/                # SQL injection defenses (sql_guard.py)
โ”œโ”€โ”€ scripts/               # check_connection, check_llm, seed_database
โ”œโ”€โ”€ alembic/                # schema migrations
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ unit/                # sql_guard, schema_service, insight_service
โ”‚   โ””โ”€โ”€ integration/          # real Neon queries
โ”œโ”€โ”€ Dockerfile, docker-compose.yml
โ””โ”€โ”€ alembic.ini

Database Schema

11 tables modeling a software consultancy: departments, employees (self-referencing manager hierarchy), clients, projects, project_assignments (many-to-many), products, orders, invoices, support_tickets, meetings, meeting_attendees (many-to-many). Full relational integrity via foreign keys, check constraints (e.g., positive order quantities, valid status enums), and indexes on frequently-filtered columns.

Installation

Prerequisites

  • Python 3.12+

  • A Neon PostgreSQL database (free tier works)

  • A Groq API key (free tier works)

  • Docker (optional, for containerized runs)

Setup

git clone <your-repo-url>
cd postgres-mcp-server
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
# fill in .env with your real Neon connection string and Groq API key

Environment Variables

Variable

Description

DATABASE_URL

Neon connection string, async form: postgresql+asyncpg://user:pass@host/db?ssl=require

GROQ_API_KEY

Your Groq API key

GROQ_MODEL

Model name (default: llama-3.3-70b-versatile)

LOG_LEVEL

Logging verbosity (default: INFO)

ENVIRONMENT

development or production

Neon Setup

  1. Create a free account and project at neon.tech

  2. Copy the connection string from your project dashboard

  3. Convert it to async form: change postgresql:// to postgresql+asyncpg://, and sslmode=require to ssl=require, dropping any channel_binding param

Database Setup

alembic upgrade head              # creates all 11 tables
python scripts/seed_database.py   # populates realistic fictional data

Running Locally

python -m postgres_mcp.server

This starts the MCP server over stdio transport. To test it interactively:

npx @modelcontextprotocol/inspector@latest python -m postgres_mcp.server

Running with Docker

docker build -t postgres-mcp-server:latest .
docker run -i --env-file .env postgres-mcp-server:latest

Or via Docker Compose:

docker compose up --build

Pre-built image available on Docker Hub:

docker pull amankhan1009/postgres-mcp-server:latest

Testing

pytest -m "not integration" -v   # unit + mocked tests (fast, no DB needed)
pytest -m integration -v          # integration tests (hits real Neon)
pytest -v                          # everything

22 tests passing: 20 unit/mocked (including full sql_guard injection-defense coverage) + 2 integration tests against real seeded data.

Example Tool Calls

list_tables()

["clients", "departments", "employees", "invoices", "meeting_attendees",
 "meetings", "orders", "products", "project_assignments", "projects", "support_tickets"]

business_insights("which department has the highest average employee salary?")

The department with the highest average employee salary is Engineering, with an average salary of $101,125.

find_related_tables("employees", max_depth=2)

{
  "table_name": "employees",
  "related_tables": {
    "departments": 1, "project_assignments": 1, "meeting_attendees": 1, "support_tickets": 1,
    "projects": 2, "clients": 2, "meetings": 2
  }
}

Security

  • All user/LLM-supplied SQL passes through sql_guard.py: single-statement enforcement, forbidden keyword/function blocking, and a hard row limit

  • Every query runs inside a READ ONLY Postgres transaction as a final safety net

  • Table names from tool inputs are validated against a live whitelist (list_tables()) before being used in any query, since identifiers can't be parameterized like values

  • Secrets are never baked into the Docker image โ€” passed only at runtime via --env-file

  • Container runs as a non-root user

Future Improvements

  • Optional, separately-hardened write capability (structured insert_row-style tools with strict table/column whitelisting, audit logging, and confirmation steps) โ€” deliberately out of scope for this version, which is read-only by design

  • Support for a second LLM provider (OpenAI/Anthropic) via the existing LLMProvider interface

  • Query result caching for repeated describe_table/list_tables calls

  • Rate limiting on execute_select and LLM-powered tools


Built as a portfolio project to demonstrate production-grade backend architecture, PostgreSQL fluency, and safe AI-database integration via MCP.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

โ€“Maintainers
โ€“Response time
โ€“Release cycle
โ€“Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Amankhan1009/postgres-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server