Atlas / MCP servers / antonorlov / mcp-postgres-server

mcp-postgres-serverBLOCK

mcp/antonorlov/mcp-postgres-server

MCP server for PostgreSQL. Works with VS Code, Cursor, Claude Code, Codex, and Windsurf.

Verdict
BLOCK
Grade
D
Trust score
68 /100
Exposed tools
6 5r · 1w · 0d
Transport
stdio
License
MIT
Stars
23
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://www.npmjs.com/package/mcp-postgres-server) [](https://github.com/antonorlov/mcp-postgres-server/actions/workflows/ci.yml)

A Model Context Protocol (MCP) server for PostgreSQL: local, Docker, RDS, Neon, and Supabase databases.

The server is small and auditable, with four runtime dependencies: the MCP SDK, pg, pg-connection-string, and zod (plus ssh2, an optional dependency used only for SSH tunneling).

Requires Node.js 20 or newer.

Quick start

The preferred way to configure the server is a single DATABASE_URL:

{
"mcpServers": {
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-postgres-server"],
"env": {
"DATABASE_URL": "postgres://user:password@localhost:5432/mydb",
"PG_ALLOW_WRITE": "false"
}
}
}
}

With PG_ALLOW_WRITE set to "false" the server has read-only access to the database. This is the default; set it to "true" only if the model must write.

The same JSON works in any MCP client that speaks stdio: VS Code, Cursor, Claude Code, Codex, Windsurf.

Alternatively, set the individual PG_* variables; they are used when DATABASE_URL is not set:

{
"mcpServers": {
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-postgres-server"],
"env": {
"PG_HOST": "your_host",
"PG_PORT": "5432",
"PG_USER": "your_user",
"PG_PASSWORD": "your_password",
"PG_DATABASE": "your_database",
"PG_ALLOW_WRITE": "false"
}
}
}
}

Manual Installation

npm install mcp-postgres-server

Or run directly with:

npx mcp-postgres-server

Connect to your database

Local Postgres:

DATABASE_URL=postgres://mcp_readonly:secret@localhost
Read from source at commit 4971cd6e29e7OBSERVED · 2026-10-12
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add mcp-postgres-server --env DATABASE_URL=${DATABASE_URL} --env PG_PASSWORD=${PG_PASSWORD} -- npx -y [email protected]
03

Exposed tools (6)

5 read · 1 write · 0 destructive.

ToolRiskDescription
connect_dbread
describe_tableread
executewrite
list_schemasread
list_tablesread
queryread
04

Trust audit

BLOCKgrade D · trust 68/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (3 observation(s))
Network
none-observed
Shell
none-observed
Dependencies
not all pinned
Secrets in source
found

Findings (17)

HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/ssh-connector.ts:82
const FINGERPRINT_HINT = 'get it with ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub (on the bastion) or ssh-keygen -lF host (from ~/.ssh/known_hosts)';
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/ssh-connector.ts:105
for (const name of ['id_ed25519', 'id_rsa', 'id_ecdsa']) {
Why it matters. touches a credential store
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
src/ssh-connector.ts:150
throw new ConnectionError('SSH_CONFIG_INVALID', 'SSH authentication required: set PG_SSH_PRIVATE_KEY, PG_SSH_AGENT, or PG_SSH_PASSWORD, or provide a default key (~/.ssh/id_ed25519) or a running agent
Why it matters. touches a credential store
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
.github/workflows/ci.yml:48
PG_TEST_URL: postgres://postgres:postgres@localhost:5432/mcp_test
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
README.md:80
DATABASE_URL=postgres://mcp_readonly:secret@localhost:5432/mydb
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
README.md:89
DATABASE_URL=postgres://mcp_readonly:[email protected]:5432/mydb
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
README.md:326
"DATABASE_URL": "postgres://mcp_readonly:[email protected]:5432/mydb?sslmode=verify-full",
MEDIUMHard-coded secrets · secret.db_uri · CWE-798, CWE-321
test/entrypoint.test.ts:33
const { proc, handlers, exited } = fakeProcess({ DATABASE_URL: 'postgres://u:p@h:5432/d' });
LOWInventory / provenance · inv.hidden_file · CWE-1104
mcpb/.mcpbignore
.mcpbignore
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
test/ssh-connector.test.ts:22
const KEY_PATH = join(dir, 'id_ed25519');
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
test/ssh-connector.test.ts:27
writeFileSync(join(HOME_WITH_KEY, '.ssh', 'id_ed25519'), 'DEFAULT-KEY-BYTES');
Why it matters. touches a credential store
LOWNetwork egress · net.tls_off · CWE-200, CWE-319
test/ssh-connector.test.ts:162
expect(sslForTunnel({ rejectUnauthorized: false }, 'db.example.com')).toEqual({ ssl: { rejectUnauthorized: false, servername: 'db.example.com' } });
Why it matters. certificate verification is disabled
Fix. leave verification on
LOWNetwork egress · net.tls_off · CWE-200, CWE-319
test/units.test.ts:208
expect(cfg.ssl).toEqual({ rejectUnauthorized: false });
Why it matters. certificate verification is disabled
Fix. leave verification on
LOWNetwork egress · net.tls_off · CWE-200, CWE-319
test/units.test.ts:230
expect(on.ssl).toEqual({ rejectUnauthorized: false });
Why it matters. certificate verification is disabled
Fix. leave verification on
LOWNetwork egress · net.tls_off · CWE-200, CWE-319
test/units.test.ts:268
expect(bare.ssl).toEqual({ rejectUnauthorized: false });
Why it matters. certificate verification is disabled
Fix. leave verification on
LOWNetwork egress · net.tls_off · CWE-200, CWE-319
test/units.test.ts:277
expect(loadConfig({ PG_HOST: 'h', PG_SSLMODE: 'prefer' }).ssl).toEqual({ rejectUnauthorized: false });
Why it matters. certificate verification is disabled
Fix. leave verification on
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@modelcontextprotocol/sdk, pg, pg-connection-string, zod, @types/node, @types/pg, @types/ssh2, @vitest/coverage-v8
Why it matters. 11 dependency range(s) float
Fix. pin exact versions or ship a lockfile

Gates applied: no_behavioural_pass.

Audited 2026-10-12 · audit v0.4.1 · source sha 4971cd6e29e7full audit observations/trust-audit/mcp-server/antonorlov__mcp-postgres-server.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-124971cd6e29e7BLOCKD68first audit
06

Questions

What is the mcp-postgres-server MCP server?

MCP server for PostgreSQL. Works with VS Code, Cursor, Claude Code, Codex, and Windsurf.

What tools does mcp-postgres-server expose?

6 in total: 5 read-only, 1 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is mcp-postgres-server safe to connect to an agent?

No — not without reading the findings first. The audit graded it D (68/100) and found 3 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does mcp-postgres-server need?

It reads DATABASE_URL and PG_PASSWORD from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does mcp-postgres-server run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as mcp-postgres-server at 0.3.1.

How current is this page?

The grade is for one exact copy of the source (4971cd6e29e7), read on 2026-10-12. The repository is watched and re-audited when it changes.

Advertisement