{"_id":"@kaiva/postgres-mcp","_rev":"3-3b098de084e95347a98de28ae214e7f2","name":"@kaiva/postgres-mcp","dist-tags":{"latest":"0.1.1"},"versions":{"0.0.0-stage":{"name":"@kaiva/postgres-mcp","version":"0.0.0-stage","_id":"@kaiva/postgres-mcp@0.0.0-stage","stub":true,"maintainers":[{"name":"kaiva","email":"info@kaiv.ai"}],"dist":{"shasum":"abf5029b39913eea0531936a72122118baacd070","tarball":"https://registry.npmjs.org/@kaiva/postgres-mcp/-/postgres-mcp-0.0.0-stage.tgz","fileCount":2,"integrity":"sha512-LmKuFUz8YDmvF8W1O9Zi1+/wbpD6nmO8rAxhrR6IqgofZltDPfAgvaW5vp1z9LdLErUc6n/EfXreB/fwVfdJ9A==","signatures":[{"sig":"MEUCIQC7Ltyzqr0ZOsRz+iJfcDfPiBYt5ZFRg+kPonBSK5ooJAIgVLjPDkPUldw9fmkunpZbOQOGhDC3XCr+cGWaG8Okpf4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":341},"_npmUser":{"name":"kaiva","email":"info@kaiv.ai"},"description":"Temporary package placeholder for staged publishing","directories":{}},"0.1.0":{"name":"@kaiva/postgres-mcp","version":"0.1.0","keywords":["mcp","model-context-protocol","postgres","postgresql","mcp-server","read-only","claude","cursor"],"author":{"url":"https://kaiv.ai","name":"Kaiva"},"license":"MIT","_id":"@kaiva/postgres-mcp@0.1.0","maintainers":[{"name":"kaiva","email":"info@kaiv.ai"}],"homepage":"https://kaiv.ai/bridge","bugs":{"email":"support@kaiv.ai"},"bin":{"kaiva-postgres-mcp":"bin/kaiva-postgres-mcp.js"},"dist":{"shasum":"92a50d9dacedbedd61905e60c6176ba18ec48f34","tarball":"https://registry.npmjs.org/@kaiva/postgres-mcp/-/postgres-mcp-0.1.0.tgz","fileCount":12,"integrity":"sha512-//JL45CIfOvJmwIOuNYDZqrpcdZN2dpiBOQ0xoMdfab/NNdpjKIagUXp1yjOSo2QlHJHv77APog+rqzJ9D98sA==","signatures":[{"sig":"MEUCIHVIlaeZNOPgI0QoD5Vmg9v6OE0ZXT7FhzxeUpDkdzexAiEA2CO6puxODEj90yk5ROGEK6A/4MHHLQ6E3xjNJRUHQyg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIAQ4yN9Uh8bdtLJSuyrBVY3xuE/xnvhqCjLEtlRQhJD4AiBonROtwylEDnUWv3ETifj9oNMLbmdfj9LjSdNygWAfxQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":80587},"type":"module","engines":{"node":">=18"},"gitHead":"a28d99fa2eeac9834f351b36f97e12632b7c9800","mcpName":"ai.kaiv/postgres","_npmUser":{"name":"kaiva","email":"info@kaiv.ai"},"repository":{"url":"git+https://github.com/ai-kaiva/postgres-mcp.git","type":"git"},"_npmVersion":"11.19.0","description":"A maintained, read-only PostgreSQL MCP server. Drop-in replacement for the archived @modelcontextprotocol/server-postgres.","directories":{},"_nodeVersion":"24.21.0","dependencies":{"pg":"8.23.1","pg-cursor":"2.22.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":true,"_npmOperationalInternal":{"tmp":"tmp/postgres-mcp_0.1.0_1792418112873_0.2929234169418713","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"_id":"@kaiva/postgres-mcp@0.1.1","bin":{"kaiva-postgres-mcp":"bin/kaiva-postgres-mcp.js"},"bugs":{"email":"support@kaiv.ai"},"dist":{"shasum":"7af70a04ed224cc30e72bbd33ce04485a0947e28","tarball":"https://registry.npmjs.org/@kaiva/postgres-mcp/-/postgres-mcp-0.1.1.tgz","fileCount":12,"integrity":"sha512-SsoNnm5owOlq+2Cw8QLblWFm6XjbYBAmu/g+1UUSXNt7uWTh7oAYviW0zml/uJa+nUYDhgzSMJcWr7KWkAU6/w==","signatures":[{"sig":"MEUCIQDH423yep0NNUo6fJw4Ql/rZGzGTAucinpGVf0wtxS8UAIgchJ7oEgVYM147o5eIWPBiH91GGgNbOoVSbLXrtgeVx4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCX6YUOlVfjTT0X6+YO66RSeh8/rus9pRPP2mfaxDmMkQIgb9UNGFcfX8xVqu+obXBtBL4LoLxj022x/trBrxGPjXo="}],"unpackedSize":81058},"name":"@kaiva/postgres-mcp","type":"module","author":{"url":"https://kaiv.ai","name":"Kaiva"},"engines":{"node":">=18"},"gitHead":"bcb5e90e0fb0bf0c1057ae7732ec4026b1615f87","license":"MIT","mcpName":"ai.kaiv/postgres","version":"0.1.1","_npmUser":{"name":"kaiva","email":"info@kaiv.ai"},"homepage":"https://kaiv.ai/bridge","keywords":["mcp","model-context-protocol","postgres","postgresql","mcp-server","read-only","claude","cursor"],"repository":{"url":"git+https://github.com/ai-kaiva/postgres-mcp.git","type":"git"},"_npmVersion":"11.19.0","description":"A maintained, read-only PostgreSQL MCP server. Drop-in replacement for the archived @modelcontextprotocol/server-postgres.","directories":{},"maintainers":[{"name":"kaiva","email":"info@kaiv.ai"}],"_nodeVersion":"24.21.0","dependencies":{"pg":"8.23.1","pg-cursor":"2.22.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":true,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/postgres-mcp_0.1.1_1792423888413_0.07399409860430439"}}},"time":{"created":"2026-10-19T13:51:59.532Z","modified":"2026-10-19T15:31:28.734Z","0.0.0-stage":"2026-10-19T13:51:59.532Z","0.1.0":"2026-10-19T13:55:12.965Z","0.1.1":"2026-10-19T15:31:28.508Z"},"bugs":{"email":"support@kaiv.ai"},"author":{"url":"https://kaiv.ai","name":"Kaiva"},"license":"MIT","homepage":"https://kaiv.ai/bridge","keywords":["mcp","model-context-protocol","postgres","postgresql","mcp-server","read-only","claude","cursor"],"repository":{"url":"git+https://github.com/ai-kaiva/postgres-mcp.git","type":"git"},"description":"A maintained, read-only PostgreSQL MCP server. Drop-in replacement for the archived @modelcontextprotocol/server-postgres.","maintainers":[{"name":"kaiva","email":"info@kaiv.ai"}],"readme":"# Kaiva Postgres MCP\n\nThe Postgres MCP server that stays read-only. A drop-in replacement for the archived\n`@modelcontextprotocol/server-postgres`.\n\n## Switch in one line\n\nWhere your AI client starts the archived server today:\n\n```json\n{\n  \"mcpServers\": {\n    \"postgres\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol/server-postgres\", \"postgresql://localhost/mydb\"]\n    }\n  }\n}\n```\n\nchange the package name:\n\n```json\n      \"args\": [\"-y\", \"@kaiva/postgres-mcp\", \"postgresql://localhost/mydb\"]\n```\n\nIn Claude Code:\n\n```sh\nclaude mcp add postgres -- npx -y @kaiva/postgres-mcp postgresql://localhost/mydb\n```\n\nThe `query` tool, its `sql` input and the table schema resources are the same, so nothing else\nchanges.\n\nOther ways in, with `DATABASE_URL` set in your environment:\n\n- Claude Code plugin: `/plugin install postgres-mcp --marketplace ai-kaiva/postgres-mcp`\n- Gemini CLI extension: `gemini extensions install https://github.com/ai-kaiva/postgres-mcp`, then\n  `gemini extensions config kaiva-postgres-mcp` to enter the database URL\n- Docker: `docker run -i --rm -e DATABASE_URL ghcr.io/ai-kaiva/postgres-mcp` once the image is published\n\n## Why switch\n\nThe archived server is no longer maintained: Anthropic archived it in 2025 as a reference example\nrather than production software, and npm marks it \"Package no longer supported\". It runs whatever\ntext it is given inside `BEGIN TRANSACTION READ ONLY`, and that is not enough:\n\n- `COMMIT; DROP SCHEMA public CASCADE` ends the read-only transaction and drops the schema\n  (reported by Datadog Security Labs in August 2025; the fix never reached npm, where 0.6.2 is\n  still the latest version).\n- With a superuser login, which is what most local and Docker installs start with, one statement\n  can run a shell command on the database server: PostgreSQL runs `COPY ... TO PROGRAM` inside a\n  read-only transaction.\n\nWe checked both against version 0.6.2 on PostgreSQL 14: both ran. Kaiva Postgres MCP refuses both.\n\n| | Archived 0.6.2 | Kaiva Postgres MCP |\n|---|---|---|\n| A second statement after `COMMIT` | Runs | Refused: one statement per call, and PostgreSQL itself refuses a second |\n| `COPY ... TO PROGRAM`, server file reads, `dblink` | Run, if the login allows | Refused |\n| Time limit | None | 15 seconds per statement, 3 seconds waiting for a lock |\n| Rows returned | All of them | The first 1,000, and it says so |\n| Superuser login | Used as given | Warning on this machine; refused for a database on another machine unless you allow it |\n| Tables listed | `public` schema only | Every schema |\n| Dates and timestamps | Turned into JavaScript dates, which can shift a date to the day before | Exactly as PostgreSQL prints them |\n| Errors | Returned as protocol errors | Returned to the AI with what to fix |\n| Maintained | No | Yes |\n\n## Tools\n\n- `query`: run one read-only SQL statement (`SELECT`, `WITH`, `VALUES`, `TABLE`, `SHOW` or\n  `EXPLAIN`) and get the rows as JSON.\n- `list_tables`: the tables and views this login can read, with type, estimated row count and\n  comment.\n- `describe_table`: one table's columns, primary key, unique and foreign keys, the tables that\n  reference it, and its indexes.\n\nResources: each table's columns, as the archived server listed them.\n\n## How read-only is enforced\n\nOn every call:\n\n1. The SQL is checked before it is sent: one statement, starting with `SELECT`, `WITH`, `VALUES`,\n   `TABLE`, `SHOW` or `EXPLAIN`, calling no function that reaches past the transaction (`dblink`,\n   server file functions, `lo_import` and `lo_export`, `pg_terminate_backend`, advisory locks, and\n   functions that run SQL given to them as text).\n2. It runs alone, through PostgreSQL's extended query protocol, which refuses a second statement,\n   inside a `READ ONLY` transaction with a statement time limit and a lock time limit.\n3. The transaction is always rolled back, and `DISCARD ALL` resets the session, so nothing a\n   statement sets up outlives it.\n\nOnly the first 1,000 rows are fetched from the database (one more is read, to know whether more\nexist), so a query over a large table returns quickly.\n\n## Use a login that can only read\n\nThe strongest guard is a login that cannot write. Run this once as an administrator, then put\n`mcp_readonly` in the connection URL:\n\n```sql\nCREATE ROLE mcp_readonly LOGIN PASSWORD 'choose-a-password';\nGRANT CONNECT ON DATABASE mydb TO mcp_readonly;\nGRANT pg_read_all_data TO mcp_readonly;  -- PostgreSQL 14 and later\nALTER ROLE mcp_readonly SET default_transaction_read_only = on;\n```\n\nTo see what a login can do:\n\n```sh\nnpx -y @kaiva/postgres-mcp postgresql://mcp_readonly:...@localhost/mydb --check\n```\n\n## Options\n\n| Option | Default | |\n|---|---|---|\n| `--max-rows <n>` | 1000 | Rows returned per query, 1 to 10000 |\n| `--timeout <seconds>` | 15 | Time limit per statement, 1 to 300 |\n| `--allow-superuser` | off | Allow a superuser login on a database on another machine. In Docker Compose the database is another container, so this applies there too; a read-only login is the better answer |\n| `--check` | | Connect once, report what the login can do, and exit |\n\nGive the connection URL as the first argument, or set `DATABASE_URL`. TLS settings go in the URL\n(`sslmode`, `sslrootcert`), as with `psql`.\n\n## What it does not protect\n\n- Anything the login can read, the AI can read: tables, views and foreign tables, and with a\n  superuser the system catalogs too (`pg_authid` holds password hashes). Use a login that sees only\n  the tables you mean to share.\n- The refused-function list is a second guard, not a sandbox. It sees the SQL the AI sends, not what\n  a view, a foreign table (`file_fdw`) or a function already defined in your database does when it\n  is read. With a superuser login such an object can still read a file on the database server. With\n  a login that can only read, PostgreSQL itself refuses (checked: a view over `pg_read_file` reads\n  the file as a superuser and is refused as a read-only login).\n- \"This machine\" means localhost, 127.x, ::1, a Unix socket, `*.localhost` and\n  `host.docker.internal` (the Docker host). Anywhere else, Docker Compose service names and private\n  network addresses included, a superuser is refused unless `--allow-superuser` is given.\n\n## In Claude.ai, ChatGPT or for your team\n\nThis package runs on your machine. To use the same database from Claude.ai or ChatGPT, or share it\nwith your team behind sign-in, Kaiva Bridge serves it as a managed MCP server. In a project folder\nwhose `.env` holds `DATABASE_URL`:\n\n```sh\nnpx @kaiva/bridge push mydb --db\n```\n\nYour database must be reachable from the internet. https://kaiv.ai/bridge?utm_source=postgres-mcp&utm_medium=readme\n\n## License\n\nMIT\n","readmeFilename":"README.md"}