Skip to main content
Glama

pg-mcp

MCP server for PostgreSQL. Query databases, inspect schemas, backup data, and manage dumps — with built-in read-only protection.

Quick Start

npm install -g @shedyhs/pg-mcp

Add to your AI provider config:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@shedyhs/pg-mcp"],
      "env": {
        "DATABASE_URL": "postgres://user:pass@localhost:5432/mydb"
      }
    }
  }
}

With DATABASE_URL or PGHOST/PGDATABASE set, the server auto-connects as "default" on startup.

Set PG_MCP_READ_ONLY=false in env to allow write operations (read-only by default).

Related MCP server: PostgreSQL MCP Server

Named Connections

To reach more than one database, give each connection a name. Every tool takes a connectionId, and pg_list_connections shows what is open.

Create ~/.config/pg-mcp/connections.json:

{
  "connections": [
    { "id": "prod", "url": "postgres://app:${PROD_PW}@prod.example.com:5432/app", "readOnly": true },
    { "id": "staging", "url": "postgres://app:${STG_PW}@stg.example.com:5432/app", "readOnly": true },
    { "id": "local", "url": "postgres://dev:dev@localhost:5432/app", "readOnly": false }
  ]
}

The path is fixed — no env var is needed to point at it. Each entry takes:

Field

Required

Meaning

id

yes

Name to pass as connectionId

url

yes

PostgreSQL connection URL

readOnly

no

Falls back to PG_MCP_READ_ONLY, then to true

Unknown keys are rejected rather than ignored, so a misspelled raedOnly fails loudly instead of silently leaving the connection read-only.

Since the file holds connection targets, chmod 600 ~/.config/pg-mcp/connections.json — the server warns on stderr if it is world-writable.

${VAR} expansion

URLs expand ${VAR} from the environment, so the file can be committed without the passwords in it:

{ "id": "prod", "url": "postgres://app:${PROD_PW}@prod.example.com:5432/app" }

Two rules matter:

  • A reference inside a larger URL is percent-encoded. A password containing @, / or # would otherwise close the userinfo section and re-parse as a different host — silently pointing the connection somewhere else. Escaping means a var cannot span URL components, so "${HOST}" holding db:5432 becomes db%3A5432; use "${HOST}:5432" instead.

  • A reference that is the whole value is used verbatim, because it stands for a complete URL:

    { "id": "prod", "url": "${PROD_DATABASE_URL}" }

A variable that is unset or empty is an error: that one connection is skipped and reported on stderr, the others still open.

Passwords in a separate file

${VAR} moves the password from the config file to the environment — but in an MCP setup that environment is usually the env block of your client config, which is plaintext all the same. To keep connections.json free of secrets, put the passwords in ~/.config/pg-mcp/credentials.json instead — a flat map of connection id to password:

{
  "prod": "the-real-password",
  "staging": "another-password"
}
chmod 600 ~/.config/pg-mcp/credentials.json

Then leave the password out of the URL entirely:

{
  "connections": [
    { "id": "prod", "url": "postgres://app@prod.example.com:5432/app", "readOnly": true }
  ]
}

The password is injected into the URL at startup, percent-encoded, so @, /, # and : in a password are safe. It applies to connections from any source, so {"default": "..."} covers one declared through DATABASE_URL too.

Three cases get reported on stderr instead of looking like a wrong password:

  • an id in credentials.json that matches no connection (a typo)

  • a credential for a connection that has no URL to inject into

  • a contested id — if two sources declare the same id, the password is refused, not applied. credentials.json is a 0600 file, but an environment variable can claim any id; applying the password anyway would hand a secret meant for one host to a URL declared somewhere less trusted. Rename one of them to resolve it.

pg_dump and pg_restore receive the password through PGPASSWORD, never as a command-line argument: on Linux /proc/PID/cmdline is world-readable (mode 444) so anything in argv shows up in ps for every user on the machine, while /proc/PID/environ is mode 600.

The file is still plaintext — this separates the secret from the config so the latter can be committed, it does not encrypt anything. The server warns if the file is readable beyond its owner, and chmod 600 silences that. (libpq's ~/.pgpass also still works, if you already keep passwords there: omit the password and the driver finds it.)

Inline via env

The same list can go in a single PG_MCP_CONNECTIONS env var, as a JSON array:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@shedyhs/pg-mcp"],
      "env": {
        "PG_MCP_CONNECTIONS": "[{\"id\":\"prod\",\"url\":\"postgres://app:${PROD_PW}@prod:5432/app\",\"readOnly\":true}]",
        "PROD_PW": "..."
      }
    }
  }
}

Precedence

All three sources are merged by id, later ones winning:

  1. ~/.config/pg-mcp/connections.json

  2. PG_MCP_CONNECTIONS

  3. DATABASE_URL, or PGHOST/PGDATABASE — these always own the id default

Passwords from credentials.json are applied after the merge, to whichever connection ended up with each id.

Connections open concurrently at startup and are registered in declaration order. When a higher-precedence source takes over an id, the override is reported on stderr, so a stray DATABASE_URL repointing a reviewed connection is visible rather than silent.

A database being unreachable never stops the server: each attempt is bounded by a 10s timeout — covering both the connect and the health check, so a host that accepts TCP but never answers cannot stall startup — and the failure goes to stderr while the other connections stay usable.

Tools

Tool

Description

Requires

pg_list_connections

List open connections with target and read-only mode (never returns credentials)

pg_connect

Connect to a PostgreSQL database (URL, params, or libpq env vars)

pg_disconnect

Disconnect from a database

pg_query

Execute SQL queries with read-only protection

pg_list_schemas

List all user schemas

pg_get_ddl

Get complete DDL (tables, indexes, constraints, FKs, sequences, enums, views)

pg_backup_query

Backup specific rows as INSERT statements before destructive operations

pg_dump

Dump a database or specific tables to a file

pg_dump CLI

pg_restore

Restore a database from a dump file (custom, directory, or tar format)

pg_restore CLI

Where to Put the Config

Provider

Config file

Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json (macOS) / %APPDATA%\Claude\claude_desktop_config.json (Windows)

Claude Code

.claude/settings.json or ~/.claude/settings.json

Cursor

.cursor/mcp.json

Windsurf

~/.codeium/windsurf/mcp_config.json

Codex

codex.json

All providers above use the same JSON format from Quick Start.

GitHub Copilot (VS Code) uses a slightly different format in .vscode/mcp.json:

{
  "servers": {
    "postgres": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@shedyhs/pg-mcp"],
      "env": {
        "DATABASE_URL": "postgres://user:pass@localhost:5432/mydb"
      }
    }
  }
}

From source — replace command/args with "command": "node", "args": ["/path/to/pg-mcp/dist/index.js"].

Installing pg_dump & pg_restore

Only needed if you use pg_dump or pg_restore. All other tools work without external dependencies.

OS

Command

macOS

brew install libpq

Debian/Ubuntu

sudo apt-get install postgresql-client-16

RHEL/Fedora

sudo dnf install postgresql16

Windows

winget install PostgreSQL.PostgreSQL.16

Verify with pg_dump --version.

Installation from Source

git clone https://github.com/shedyhs/pg-mcp
cd pg-mcp
npm install && npm run build

License

MIT

Available Tools

5 tools
pg_connectB

Connect to a PostgreSQL database using a URL or individual parameters

ParametersJSON Schema
NameRequiredDescriptionDefault
connectionIdYesUnique identifier for this connection
urlNoPostgreSQL connection URL (e.g., postgresql://user:pass@host:5432/dbname?ssl=true)
hostNoPostgreSQL host (ignored if url is provided)
portNoPostgreSQL port (default: 5432, ignored if url is provided)
databaseNoDatabase name (ignored if url is provided)
userNoUsername (ignored if url is provided)
passwordNoPassword (ignored if url is provided)
sslNoUse SSL connection (default: false, ignored if url is provided)
readOnlyNoEnable read-only mode - blocks INSERT, UPDATE, DELETE, and DDL operations (default: true)

TDQS

B3.2/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must fully disclose behavior. It only states the connection method but omits what happens on success/failure, whether connections are pooled, or any side effects. The readOnly parameter is not mentioned in the description, though it is in the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, effective sentence that immediately conveys the core purpose. It is front-loaded and contains no extraneous information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (9 parameters, no annotations, no output schema), the description is too minimal. It fails to explain the return behavior (e.g., what happens after connecting), error handling, or how to use the connection with sibling tools. The schema covers parameter details, but the description should provide broader context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds a high-level distinction between URL and individual parameters, which echoes the schema's 'ignored if url is provided' notes. It does not add substantial new meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly specifies the action ('Connect') and the resource ('PostgreSQL database'), and distinguishes between two connection methods (URL or individual parameters). This clearly differentiates it from sibling tools like pg_disconnect, pg_query, etc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives (e.g., before querying, after disconnect). It does not mention prerequisites, such as needing a connectionId, or that it must be called before other database operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pg_disconnectB

Disconnect from a PostgreSQL database

ParametersJSON Schema
NameRequiredDescriptionDefault
connectionIdYesConnection ID to disconnect

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, and the description only states the basic action. It does not disclose side effects (e.g., rolling back transactions), error conditions, or whether repeated disconnects are safe.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence, front-loaded with the essential action. No superfluous words; every word contributes to the purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter tool, the description covers the core action but lacks behavioral context (e.g., prerequisites, side effects). Adequate but with gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single parameter 'connectionId', and the description does not add any additional meaning beyond what the schema already provides. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action 'Disconnect' and the resource 'PostgreSQL database', which is specific and distinct from sibling tools like pg_connect, pg_get_ddl, etc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool, prerequisites (e.g., must have an active connection), or alternatives. The description does not help the agent decide when to invoke it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pg_get_ddlA

Get the complete DDL (Data Definition Language) of the database including CREATE TABLE statements, indexes, constraints, foreign keys, sequences, and views

ParametersJSON Schema
NameRequiredDescriptionDefault
connectionIdYesConnection ID to use
schemaNoFilter by schema (optional, returns all user schemas if not specified)

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Given no annotations, the description carries full burden. It indicates a read operation returning DDL content, but could add statements about non-destructiveness or potential performance impact on large databases.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence with precise content; no unnecessary words. Efficiently conveys purpose and scope.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Without an output schema, the description reasonably describes the output (DDL statements). Missing explicit mention of return format (e.g., string or array), but still informative.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with clear parameter descriptions, so baseline is 3. The description adds no extra meaning beyond the schema; it only reiterates the schema's optionality note.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the verb 'Get', the resource 'complete DDL', and lists included objects (CREATE TABLE, indexes, etc.), clearly distinguishing it from sibling tools like pg_query or pg_list_schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use when DDL is needed, but provides no explicit when-to-use, when-not-to-use, or alternative guidance. It is adequate but lacks direct differentiation from pg_query or pg_list_schemas.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pg_list_schemasA

List all schemas in the database

ParametersJSON Schema
NameRequiredDescriptionDefault
connectionIdYesConnection ID to use

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided. The description indicates a read-only operation ('list'), but lacks details on permissions, performance, or potential side effects. For a simple read tool, minimal transparency is acceptable but not exceptional.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence with no wasted words. It is front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one required parameter, no output schema), the description provides sufficient context for an agent to understand its purpose. A minor improvement would be to indicate the return format (e.g., list of schema names), but it is not mandatory.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers 100% of parameters, and the description adds no additional meaning beyond the schema's own description of the connectionId parameter. Baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists all schemas in the database, using a specific verb and resource. It is distinct from sibling tools like pg_connect (connection management) and pg_query (arbitrary queries).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when schemas need to be enumerated, but does not provide explicit guidance on when to use versus siblings, nor any preconditions (e.g., needing an active connection).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pg_queryC

Execute a SQL query on a PostgreSQL database

ParametersJSON Schema
NameRequiredDescriptionDefault
connectionIdYesConnection ID to use
sqlYesSQL query to execute
paramsNoQuery parameters for prepared statements

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must fully disclose behavioral traits. It does not mention whether the query can modify data, require specific permissions, or produce side effects. The minimal description leaves significant gaps in understanding the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single short sentence, which is concise but under-informative for a significant operation. It is not overlong, but additional context could be incorporated without losing conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of annotations and output schema, the description is too sparse. It omits details on return format, error handling, security (e.g., SQL injection mitigation via params), and proper usage of parameters. In comparison to sibling tools, it provides insufficient context for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so parameters have descriptions. The tool description adds no extra meaning beyond the schema; for example, 'sql' is described as 'SQL query to execute' which repeats the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Execute') and resource ('SQL query on a PostgreSQL database'). It is specific and unambiguous, though it does not explicitly differentiate from sibling tools like pg_get_ddl, which also executes queries for DDL. A score of 4 reflects clarity without sibling distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use pg_query versus alternatives like pg_get_ddl or pg_list_schemas. There is no mention of appropriate use cases, prerequisites, or exclusions. The agent receives no contextual advice for selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 5 tool updatesv1.0.0
    • First observedpg_connect
    • First observedpg_disconnect
    • First observedpg_get_ddl
    • First observedpg_list_schemas
    • First observedpg_query

TDQS

A3.7/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a distinct purpose: connection management, schema listing, DDL retrieval, and arbitrary query execution. No overlap or ambiguity.

Naming Consistency5/5

All tools use the 'pg_' prefix followed by a verb_noun pattern (connect, disconnect, get_ddl, list_schemas, query). Naming is consistent and predictable.

Tool Count5/5

With 5 tools, the server covers essential database operations without being too sparse or overwhelming. The count is well-scoped for its purpose.

Completeness4/5

The server provides core functionality for connecting, exploring schemas, viewing DDL, and running queries. It lacks dedicated tools for listing tables or indexes, but the SQL query tool can compensate.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to interact with PostgreSQL databases through the Model Context Protocol, providing database schema exploration, table structure inspection, and SQL query execution capabilities.
    15
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to safely interact with PostgreSQL databases through read-only operations, providing schema discovery, table inspection, and query execution capabilities with structured context awareness.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to query, explore, and analyze PostgreSQL databases through the Model Context Protocol. It provides robust security features including read-only mode, schema restrictions, and query timeouts for safe data interaction.
    4 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to interact with PostgreSQL databases by executing SQL queries and inspecting database schemas. It provides tools to facilitate database exploration and management through the Model Context Protocol.
    -