PostgreSQL MCP server for schema inspection, data exploration, and query execution.
Project description
pglens
A PostgreSQL MCP server with tools for schema inspection, data exploration, query execution, and database health monitoring.
Motivation
Most Postgres MCP servers expose query and list_tables, and that's about it. Agents end up guessing column names, enum values, and join paths, which leads to multiple failed attempts before landing on working SQL.
pglens adds the tools that close those gaps: checking what values actually exist in a column, discovering foreign-key relationships, previewing sample data, and validating query plans. The idea is straightforward: let the agent look before it leaps.
Tools
Schema and discovery
| Tool | What it does |
|---|---|
list_schemas |
Schemas with table and view counts |
list_tables |
Tables with row counts and descriptions |
list_views |
Views with their SQL definitions |
list_extensions |
Installed extensions and versions |
describe_table |
Columns, types, PKs, FKs, indexes, check constraints |
find_related_tables |
FK relationships in both directions |
find_join_path |
Multi-hop join paths between two tables via foreign keys |
list_functions |
Stored functions/procedures with source code |
list_triggers |
Triggers on a table with definitions and status |
list_policies |
Row-level security policies on a table |
Data exploration
| Tool | What it does |
|---|---|
sample_rows |
Random rows from a table |
column_values |
Distinct values with frequency counts |
column_stats |
Min, max, null fraction, distinct count, common values |
search_data |
Case-insensitive search across text columns |
search_columns |
Find columns by name across all tables |
search_enum_values |
Enum types and their allowed values |
Query execution
| Tool | What it does |
|---|---|
explain_query |
Query plan without execution |
query |
Read-only SQL with limit/offset pagination (default 500 rows) |
Performance and health
| Tool | What it does |
|---|---|
table_stats |
Index hit rates, dead tuples, vacuum timestamps |
table_sizes |
Disk usage per table, ranked by size |
unused_indexes |
Indexes that are never scanned |
bloat_stats |
Dead tuples, vacuum status, wraparound risk |
active_queries |
Currently running sessions and their queries |
blocking_locks |
Lock wait chains (who blocks whom) |
sequence_health |
Sequences approaching exhaustion |
matview_status |
Materialized view freshness and refresh eligibility |
Safety before DDL
| Tool | What it does |
|---|---|
object_dependencies |
What depends on a given object (views, functions, constraints) |
There is also a query_guide prompt that describes a reasonable workflow for using these tools together.
A note on column_values
Agents frequently write WHERE status = 'active' when the actual value is 'Active' or 'enabled'. column_values returns the real distinct values in a column with counts, so the agent can pick the right one instead of guessing.
Installation
pip install pglens
Or with uv:
uv pip install pglens
Usage
pglens reads standard PostgreSQL environment variables.
export PGHOST=localhost
export PGUSER=myuser
export PGPASSWORD=mypassword
export PGDATABASE=mydb
pglens
Alternatively, set a connection string via PGLENS_DSN:
export PGLENS_DSN="postgresql://myuser:mypassword@localhost:5432/mydb"
pglens
When PGLENS_DSN is set, it takes precedence over individual PG* environment variables.
By default the server uses stdio transport. To run as an HTTP server for remote use:
pglens --transport streamable-http
| Flag | Choices | Default | Description |
|---|---|---|---|
--transport |
stdio, streamable-http |
stdio |
MCP transport type |
Claude Desktop
{
"mcpServers": {
"pglens": {
"command": "pglens",
"env": {
"PGHOST": "localhost",
"PGPORT": "5432",
"PGUSER": "myuser",
"PGPASSWORD": "mypassword",
"PGDATABASE": "mydb"
}
}
}
}
Claude Code
{
"mcpServers": {
"pglens": {
"command": "pglens",
"env": {
"PGHOST": "localhost",
"PGDATABASE": "mydb"
}
}
}
}
Zed
{
"context_servers": {
"pglens": {
"command": {
"path": "pglens",
"args": []
}
}
}
}
Architecture
adapters/tools/*.py (MCP tool definitions, organized by category)
|
adapters/mcp_adapter.py (FastMCP server, lifespan, pool management)
|
adapters/asyncpg_adapter.py (SQL queries, asyncpg pool)
|
PostgreSQL
AsyncpgDatabase holds the asyncpg pool and all query methods. Tool modules in adapters/tools/ are thin wrappers that register MCP tools via decorators and delegate to it. All queries use pure pg_catalog introspection — no PostgreSQL extensions required.
Adding a tool
- Add a method to
AsyncpgDatabaseinadapters/asyncpg_adapter.py - Add a
@mcp.tool()function in the appropriateadapters/tools/*.pymodule
Safety
- All user-influenced queries run inside
readonly=Truetransactions - Table and column identifiers are escaped via PostgreSQL's
quote_ident() - No DDL tools are exposed
Requirements
- Python 3.11+
- PostgreSQL
License
MIT
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 pglens-0.3.0.tar.gz.
File metadata
- Download URL: pglens-0.3.0.tar.gz
- Upload date:
- Size: 95.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21bec97dd7074d2296bd56b171a975e36f99772297a878f0be29d3b63c1c83e7
|
|
| MD5 |
12ac1df07c892e41312a54615f4c83a2
|
|
| BLAKE2b-256 |
7f41bd6b277d66d331ca34f14ed8780061641d18c8cf96acbfcc0ef78450d7e7
|
Provenance
The following attestation bundles were made for pglens-0.3.0.tar.gz:
Publisher:
release.yml on janbjorge/pglens
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pglens-0.3.0.tar.gz -
Subject digest:
21bec97dd7074d2296bd56b171a975e36f99772297a878f0be29d3b63c1c83e7 - Sigstore transparency entry: 1200757022
- Sigstore integration time:
-
Permalink:
janbjorge/pglens@dc7f4c329ee53ba5a1fcb6c371af94231abd23d8 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/janbjorge
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dc7f4c329ee53ba5a1fcb6c371af94231abd23d8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pglens-0.3.0-py3-none-any.whl.
File metadata
- Download URL: pglens-0.3.0-py3-none-any.whl
- Upload date:
- Size: 20.7 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 |
c8efcde5ac494dd438abaf3994981efbee677f4dee31a07303337c1d43985f77
|
|
| MD5 |
14de3757e4847cb46570f70e113cd240
|
|
| BLAKE2b-256 |
b84f566015bb4599b13a40aa997a6f9c3aeaf0605fa68e879f4214f8e427ac3f
|
Provenance
The following attestation bundles were made for pglens-0.3.0-py3-none-any.whl:
Publisher:
release.yml on janbjorge/pglens
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pglens-0.3.0-py3-none-any.whl -
Subject digest:
c8efcde5ac494dd438abaf3994981efbee677f4dee31a07303337c1d43985f77 - Sigstore transparency entry: 1200757042
- Sigstore integration time:
-
Permalink:
janbjorge/pglens@dc7f4c329ee53ba5a1fcb6c371af94231abd23d8 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/janbjorge
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dc7f4c329ee53ba5a1fcb6c371af94231abd23d8 -
Trigger Event:
push
-
Statement type: