Skip to main content
Glama
MCP PostgreSQL Server
by MOmayr

MCP PostgreSQL Server

MCP server that gives an agent a PostgreSQL connection and a fixed set of tools. The server holds the connection, runs the SQL, and returns rows. The agent does not open pg itself.

The primary purpose is normal database work: connect, inspect the schema, run reads, check SQL, and run writes. Search and embedding tools are a second layer. They run when the database has pgvector.

What it does

PostgreSQL. connect_db opens the connection. list_schemas, list_tables, and describe_tables show the agent what it can query. describe_tables includes primary keys, defaults, PostGIS geometry(type, srid) and geography(type, srid), and vector / halfvec types when those catalogs exist. query runs SELECT, WITH, and EXPLAIN. execute runs INSERT, UPDATE, and DELETE. validate_sql runs EXPLAIN and returns true or the error. resolve_mentions ranks name matches with pg_trgm (similarity or word_similarity). Parameters use $1 or ?.

pgvector. list_vector_tables finds vector and halfvec columns. vector_search sends the query text to an OpenAI-compatible /v1/embeddings endpoint (vLLM, Ollama, or a hosted API), then ranks rows in PostgreSQL with cosine, L2, or inner product. Pass text_column to fuse that ranking with English full text or trigrams. The fused score keeps a closer embedding ahead of a weak keyword hit. vector_execute embeds text and inserts or updates the vector column. The agent passes text. The server fetches the embedding, checks its length against the column, and binds it as a query parameter.

PostgreSQL tools need only a database connection. list_vector_tables needs the vector extension. vector_search and vector_execute also need EMBEDDING_URL and EMBEDDING_MODEL.

Related MCP server: PostgreSQL MCP Server

Why this shape

  • query accepts only SELECT, WITH, and EXPLAIN. execute accepts only INSERT, UPDATE, and DELETE. A read-only database role still blocks writes if execute is called.

  • Schema output includes GIS and vector types, so the agent can write SQL that matches the column.

  • Vector tools take text. The agent does not build or paste embedding arrays.

  • One search call accepts up to 20 strings and can return JSON or one markdown table per string.

  • stdio serves a local MCP client. Streamable HTTP serves a remote client, and each session can name its own database in X-PG-* headers. Embedding settings stay process-wide.

Requirements

  • Node.js 20 or newer

  • PostgreSQL, for every tool

  • pg_trgm, for resolve_mentions and for hybrid search with lexical: "trgm"

  • vector extension for list_vector_tables

  • vector extension, plus EMBEDDING_URL and EMBEDDING_MODEL, for vector_search and vector_execute

pgvector HNSW indexes on vector support at most 2000 dimensions. For a 2560-dimension model such as Qwen3-Embedding-4B, store the column as halfvec(2560).

Install

From a clone:

npm install
npm run build

Or, once published:

npx -y mcp-postgres-server

Configuration

Database credentials and embedding settings are not interchangeable. Put each group in the file below and leave it out of the other.

What

Where

Variables

Database, stdio

MCP client env, or config-stdio.json for the Inspector

PG_HOST, PG_PORT, PG_USER, PG_PASSWORD, PG_DATABASE

Database, HTTP

X-PG-* headers on initialize, or the same PG_* variables in the process environment

X-PG-Host, X-PG-Port, X-PG-User, X-PG-Password, X-PG-Database

Embeddings

.env in this repo

EMBEDDING_URL, EMBEDDING_MODEL, EMBEDDING_DIMENSIONS, EMBEDDING_API_KEY

On startup the server loads .env and fills only variables the process does not already have. The stdio client starts the process with PG_* already set, so those values stay. .env then supplies the embedding endpoint. Several stdio entries can point at different databases and still share one .env.

connect_db can replace the database connection after startup. It does not read .env, and it does not change the embedding endpoint.

EMBEDDING_TIMEOUT_MS (default 30000), EMBEDDING_MAX_RESPONSE_BYTES (default 52428800), PORT (default 3000), and TRANSPORT (http or stdio) have defaults. They are not in the example files. Set them in the process environment only when you need a different value.

Local files and git

Committed files use placeholders. Copy them and put real hosts, passwords, and URLs only in the gitignored copies.

Commit this

Keep local (gitignored)

What to put in it

.env.example

.env

Embedding endpoint only

config-stdio.example.json

config-stdio.json

Database credentials for npm run inspector

config.example.json

config.json

HTTP Inspector client: URL plus X-PG-* headers

grants.sql is site-specific and gitignored. It is not part of the server.

cp .env.example .env
cp config-stdio.example.json config-stdio.json
cp config.example.json config.json

On Windows PowerShell:

Copy-Item .env.example .env
Copy-Item config-stdio.example.json config-stdio.json
Copy-Item config.example.json config.json

Edit the copies. Do not put hosts, passwords, API keys, or internal URLs in the example files.

Environment

Variable

Set in

Required

Purpose

PG_HOST

stdio env, or X-PG-Host

yes, unless connect_db supplies it

Database host

PG_PORT

stdio env, or X-PG-Port

no

Default 5432

PG_USER

stdio env, or X-PG-User

yes, same as host

Database user

PG_PASSWORD

stdio env, or X-PG-Password

yes, same as host

Database password

PG_DATABASE

stdio env, or X-PG-Database

yes, same as host

Database name

EMBEDDING_URL

.env

vector tools only

OpenAI-compatible endpoint, for example http://localhost:8000/v1/embeddings

EMBEDDING_MODEL

.env

vector tools only

Model name sent to that endpoint

EMBEDDING_DIMENSIONS

.env

no

Reject a response whose length does not match. Not sent to the API

EMBEDDING_API_KEY

.env

no

Sent as Authorization: Bearer

EMBEDDING_TIMEOUT_MS

process env

no

Default 30000

EMBEDDING_MAX_RESPONSE_BYTES

process env

no

Default 52428800

PORT

process env

no

HTTP listen port. Default 3000

TRANSPORT

process env

no

http selects the HTTP transport. Default is stdio

stdio

Default transport. Put only PG_* in the client env. Leave EMBEDDING_* in .env.

{
  "mcpServers": {
    "postgres": {
      "command": "node",
      "args": ["build/index.js"],
      "env": {
        "PG_HOST": "localhost",
        "PG_PORT": "5432",
        "PG_USER": "postgres",
        "PG_PASSWORD": "postgres",
        "PG_DATABASE": "postgres"
      }
    }
  }
}

Use the absolute path to build/index.js when the client does not start in this directory.

Streamable HTTP

npm start

That builds and runs node build/index.js --http. TRANSPORT=http does the same.

Method

Path

Role

POST

/mcp

Initialize and tool calls

GET

/mcp

Server-to-client stream

DELETE

/mcp

End the session

GET

/health

{ "status": "ok", ... }

Send database credentials on the initialize request. Later calls in that session reuse them. If the headers are absent, the server uses PG_* from the process environment. Embedding settings still come from .env. config.example.json is an Inspector client config for this transport: it has the server URL and the X-PG-* headers, not the embedding variables.

Inspector

npm run inspector

That reads config-stdio.json. Copy it from config-stdio.example.json first.

Tools

PostgreSQL

These run against the connected database. pgvector is not required.

Tool

What it does

connect_db

Connect with host, user, password, database, and optional port. Replaces the current connection.

query

Run SELECT, WITH, or EXPLAIN. Optional params.

validate_sql

Run EXPLAIN on sql. Returns the string true, or the error message.

execute

Run INSERT, UPDATE, or DELETE. Returns rowCount and command.

list_schemas

List schema names.

list_tables

List tables. Optional schema (default public).

describe_tables

Structure for a comma-separated tables list. Optional schema. Includes PostGIS geometry(type, srid) and geography(type, srid) when those catalogs exist.

resolve_mentions

Trigram search. mentions is one or more strings (max 20). Results are candidates, not confirmed matches.

pgvector

These need the vector extension and EMBEDDING_URL plus EMBEDDING_MODEL in .env. list_vector_tables only needs the extension.

Tool

What it does

list_vector_tables

Tables that have a vector or halfvec column.

vector_search

Embed each string in query and rank with pgvector. Optional hybrid search fuses that ranking with full text or trigrams without letting a weak keyword hit outrank a clearly closer embedding.

vector_execute

Embed text and insert or update the vector column.

SQL

{
  "sql": "SELECT id, name FROM places WHERE id = $1",
  "params": [1]
}

execute uses the same sql and params shape. Use query for SELECT.

Mentions

{
  "table": "places",
  "text_column": "name",
  "mentions": ["harbour", "old town"],
  "operator": "trgm",
  "limit": 5,
  "response_format": "markdown"
}

operator is trgm (default) or word. where is a SQL fragment without the WHERE keyword. include_scores defaults to true.

One string returns rows. Several strings run the same search once per string and return a group per string.

{
  "table": "documents",
  "embedding_column": "embedding",
  "query": ["permits near the river"],
  "where": "status = 'active'",
  "columns": ["id", "content"],
  "limit": 10
}

Hybrid search: set text_column. lexical is fts (default) or trgm.

  • fts uses English full text. It stems, drops stop words, keeps Arabic, drops query terms that appear in more than 40% of rows, and ranks the rest by inverse document frequency. Use it on a passage column.

  • trgm uses word_similarity() above pg_trgm.word_similarity_threshold. Use it on a short name column that has a trigram index.

{
  "schema": "catalog",
  "table": "documents",
  "embedding_column": "embedding",
  "text_column": "body",
  "lexical": "fts",
  "query": ["archaeological sites", "district boundaries"],
  "response_format": "markdown",
  "limit": 10
}

metric is cosine (default), l2, or ip. It must match the HNSW operator class for the index to be used. A where clause sets hnsw.iterative_scan=strict_order for that query. The default payload omits the embedding column and columns named hash or ending in _hash. include_scores defaults to true and adds distance, plus rrf, dense_rank, and lexical_rank on hybrid search. rrf is the sort score: for cosine, similarity plus at most 0.05 for the strongest lexical hit.

Vector write

vector_execute writes the vector column only. Delete rows, or change other columns, with execute.

Insert embeds text. text_column also stores that text. fields sets other columns.

{
  "operation": "insert",
  "table": "documents",
  "embedding_column": "embedding",
  "text": "River permit application",
  "text_column": "content",
  "fields": { "status": "active" }
}

Update with text must match one row (id, or a where that returns a single row). Update with text_column embeds that varchar on each matched row. id_column defaults to id. limit defaults to 10 and caps at 100.

{
  "operation": "update",
  "schema": "catalog",
  "table": "documents",
  "embedding_column": "embedding",
  "text_column": "body",
  "where": "body IS NOT NULL AND embedding IS NULL",
  "limit": 10
}

Development

npm install
npm run watch
npm run inspector
npm run start:http

npm start builds, then starts the HTTP transport.

Security

Queries use parameters. Identifiers passed to the vector and mention tools are restricted to simple names. where is a SQL fragment, so give the database role only the rights the agent should have. Prefer a read-only role when the agent does not need to write.

Do not commit .env, config.json, or config-stdio.json.

License

MIT

Available Tools

11 tools
connect_dbC

Connect to PostgreSQL database.

Inputs: host (required), user (required), database (required), password (required), +1 more.

describe_tablesC

Get table structure for single or multiple tables

Inputs: tables (required), schema.

executeB

Execute an INSERT, UPDATE, or DELETE query

Inputs: sql (required), params.

list_schemasA

List all schemas in the database

Inputs: no named parameters.

list_tablesC

List tables in the database

Inputs: schema.

list_vector_tablesA

List tables that have pgvector columns (vector or halfvec), with schema, column, and data type.

Inputs: no named parameters.

queryC

Execute a SELECT query

Inputs: sql (required), params.

resolve_mentionsC

Trigram search. Resolve mentioned entities to database matches. Returned rows are candidates, not confirmed matches.

Inputs: table (required), mentions (required), text_column (required), limit, +6 more.

validate_sqlB

Validate SQL. Returns the string 'true' if the SQL is valid, or an error message string if invalid.

Inputs: sql (required).

vector_executeA

Insert or update a vector/halfvec column by embedding text. insert: embed text (optional fields, optional persist via text_column). update: write only the vector. Source is text (single row: id, or where that matches one row) or text_column (embed each matched row, where/id, optional limit). Use execute for delete and non-vector columns.

Inputs: table (required), operation (required), embedding_column (required), id, +7 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 11 tools

    Disambiguation4/5

    Most tools are clearly distinct: query (SELECT) vs execute (DML), list_* vs describe_*, and vector_search vs resolve_mentions have different modalities. Minor overlap exists between query and execute (both run SQL, split by statement type) and between vector_search and resolve_mentions (both search), but descriptions help disambiguate.

    Naming Consistency3/5

    Most tools follow a verb_noun or verb_noun_phrase pattern (connect_db, validate_sql, list_schemas, describe_tables, vector_search). However, 'query' and 'execute' are bare verbs that break the pattern, and 'resolve_mentions' is more descriptive than action-oriented. The mix is readable but not fully consistent.

    Tool Count5/5

    11 tools is well within the ideal range for a database server and each tool covers a distinct capability (connection, querying, validation, schema introspection, vector operations). No tool feels redundant or excessive.

    Completeness3/5

    Core row-level CRUD is covered (query for SELECT, execute for INSERT/UPDATE/DELETE) and schema introspection plus vector features are present. However, there is no DDL support (CREATE/ALTER/DROP), no transaction control, and no explicit disconnect, which are notable gaps for a general PostgreSQL server.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      Provides AI assistants with safe, controlled access to PostgreSQL databases with read-only defaults, granular permissions, query safety features, and schema introspection capabilities.
      1
      -
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to interact with PostgreSQL databases through schema intelligence, query execution, and DBA tooling including index analysis and health monitoring. Features configurable access levels and audit logging for secure database operations.
      432 npm
      MIT