@yawlabs/postgres-mcp 0.11.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.1] - 2026-08-23
11
+
12
+ ### Fixed
13
+ - **Windows: the launcher no longer hard-kills the server on the first Ctrl-C.** There are no POSIX signals on Windows — `child.kill(sig)` ignores the name and calls `TerminateProcess`, an immediate hard kill (verified: a child with a `SIGTERM` handler never runs it and dies with `code=null`). The launcher forwarded anyway, on the stated assumption that this was a "no-op on Windows", so it aborted the graceful shutdown the console's own Ctrl-C had just started and skipped the server's `process.on("exit")` cleanup. The console already delivers the event to the whole process group, so on Windows the launcher now forwards nothing.
14
+ - **A wedged server no longer leaves the launcher hanging.** Forwarding was gated on `child.killed`, which records only that `kill()` was *called* — never that the child is gone — so every signal after the first was swallowed and there was no escape hatch. Escalation is now armed by a timer on the first signal: one press is enough, and a child still alive after a 2s grace window is killed. Using a timer rather than counting signals also stops the ordinary supervisor sequence (`SIGINT` then `SIGTERM` milliseconds apart) from being misread as impatience.
15
+
16
+ ### Documentation
17
+
18
+ - **The README now carries a "What's new in 0.11.0" section.** The three
19
+ breaking changes lived only in this file, where someone upgrading from
20
+ 0.10.x is unlikely to look before their first failing call -- and the
21
+ stats-envelope change fails at the call site rather than at install time,
22
+ since `data` becomes an object where it used to be an array.
23
+ - **Both WSL scripts and the README document the `MSYS_NO_PATHCONV=1` prefix
24
+ they require when invoked from Git Bash on Windows.** Without it, Git Bash
25
+ rewrites the `/mnt/c/...` argument into the Git install prefix before
26
+ `wsl.exe` sees it, and the script exits "No such file or directory" having
27
+ run no tests at all. Piping either script into `tail`/`head` is also called
28
+ out, because the pipeline's exit status is the last command's -- so a red
29
+ matrix reports success.
30
+
10
31
  ## [0.11.0] - 2026-08-23
11
32
 
12
33
  ### Added
package/README.md CHANGED
@@ -11,6 +11,23 @@ Built and maintained by [Yaw Labs](https://yaw.sh).
11
11
 
12
12
  One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
13
13
 
14
+ ## What's new in 0.11.0
15
+
16
+ PostgreSQL 18 support, a new I/O observability tool, and version-gated catalog queries. Full detail in the [CHANGELOG](CHANGELOG.md).
17
+
18
+ **Three breaking changes if you are upgrading from 0.10.x:**
19
+
20
+ 1. **`pg_seq_scan_tables`, `pg_unused_indexes` and `pg_top_queries` return an envelope, not a bare row array.** Read `data.rows` where you used to read `data`. The envelope carries `stats_reset`, because a cumulative scan count means nothing without knowing when the counters were last reset -- if that happened an hour ago, every index looks unused, which is how a load-bearing index gets dropped.
21
+ 2. **`pg_explain` with `analyze: true` now emits `BUFFERS`**, matching what PostgreSQL 18 does server-side. Plans get longer; pass `buffers: false` for the old output.
22
+ 3. **Node 22 is the floor.** Node 20 reached end of life.
23
+
24
+ **Worth knowing even if you are not upgrading yet:**
25
+
26
+ - `pg_describe_table` now flags generated and identity columns. Previously a generated column's expression surfaced as `default_value` with nothing marking it, so an agent read the column as optional-with-a-default and wrote an `INSERT` that PostgreSQL rejects.
27
+ - New `pg_io_stats` exposes `pg_stat_io` (PG16+) plus in-flight async I/O from `pg_aios` and the active `io_method` (PG18+).
28
+ - `pg_advisor` checks multixact wraparound alongside transaction-ID wraparound. A lock-heavy workload can exhaust multixacts while `relfrozenxid` still looks healthy.
29
+ - Every version-dependent column is gated on `server_version_num`, so older servers get a thinner answer rather than an error.
30
+
14
31
  ## Backstory
15
32
 
16
33
  Anthropic's reference Postgres MCP server, `@modelcontextprotocol/server-postgres`, was [archived in May 2025](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/postgres) and [marked deprecated on npm](https://www.npmjs.com/package/@modelcontextprotocol/server-postgres) in July 2025. Anthropic has not shipped a replacement. Despite the deprecation, the last published version (v0.6.2) is still pulled ~20,000 times per week - a lot of agents are pointed at an unmaintained package.
@@ -268,16 +268,51 @@ if (mode === "node") {
268
268
  void runInProcess();
269
269
  });
270
270
 
271
- // Forward termination so the server's own SIGINT/SIGTERM cleanup (pool
272
- // drain) runs in the child instead of the child being orphaned. Signals
273
- // are a no-op on Windows but harmless to register.
271
+ // Forward termination so the server's own shutdown path runs in the child
272
+ // rather than the child being orphaned.
273
+ //
274
+ // Registering ANY handler for these suppresses Node's default
275
+ // terminate-on-signal, so the parent's exit has to be arranged explicitly.
276
+ // `child.killed` only records that kill() was CALLED, never that the child
277
+ // is gone, so gating on it swallows every signal after the first and wedges
278
+ // the launcher with no escape hatch.
279
+ //
280
+ // Escalation is driven by a TIMER, not by counting signals. Counting is
281
+ // ambiguous: a supervisor routinely sends SIGINT then SIGTERM milliseconds
282
+ // apart, and a terminal Ctrl-C reaches the whole process group, so reading
283
+ // "a second signal" as impatience hard-kills a child that is already
284
+ // shutting down cleanly. A timer makes the count irrelevant -- ONE press is
285
+ // enough, and a wedged child dies on schedule. setTimeout is monotonic, so
286
+ // a wall-clock step cannot mis-gate the window either.
287
+ //
288
+ // POSIX vs Windows, and why we do NOT forward on Windows.
289
+ // On POSIX child.kill(sig) delivers a real, catchable signal, so forwarding
290
+ // is what lets the child run its shutdown. On Windows there are no POSIX
291
+ // signals: child.kill IGNORES the name and calls TerminateProcess -- an
292
+ // immediate hard kill (verified: a child with a SIGTERM handler never runs
293
+ // it and dies with code=null, signal=SIGTERM). Forwarding there ABORTS the
294
+ // graceful shutdown the console's own Ctrl-C just started, skipping the
295
+ // child's process.on("exit") cleanup. The console has already notified the
296
+ // child, so on Windows the timer below is the only kill we issue.
297
+ const ESCALATE_AFTER_MS = 2000;
298
+ let escalation = null;
274
299
  for (const sig of ["SIGINT", "SIGTERM"]) {
275
300
  process.on(sig, () => {
276
- if (!child.killed) child.kill(sig);
301
+ // No try/catch: kill() on an already-exited child returns false, it does
302
+ // not throw. It throws only for a signal the platform does not know,
303
+ // which SIGINT/SIGTERM/SIGKILL never are.
304
+ if (!isWin) child.kill(sig);
305
+ if (escalation) return; // already counting down; further signals are noise
306
+ escalation = setTimeout(() => {
307
+ // Still here after its grace window. Stop waiting on it.
308
+ child.kill("SIGKILL");
309
+ process.exit(128 + (constants.signals[sig] ?? 15));
310
+ }, ESCALATE_AFTER_MS);
277
311
  });
278
312
  }
279
313
 
280
314
  child.on("exit", (code, signal) => {
315
+ if (escalation) clearTimeout(escalation);
281
316
  // Mirror the child's fate: a signal death becomes 128+n so callers see a
282
317
  // conventional shell exit status rather than a bare 0.
283
318
  if (signal) {
package/dist/index.js CHANGED
@@ -39017,7 +39017,7 @@ function compareVersions(a, b) {
39017
39017
  }
39018
39018
 
39019
39019
  // src/index.ts
39020
- var version2 = true ? "0.11.0" : await readPackageVersion();
39020
+ var version2 = true ? "0.11.1" : await readPackageVersion();
39021
39021
  var subcommand = process.argv[2];
39022
39022
  if (subcommand === "version" || subcommand === "--version") {
39023
39023
  console.log(version2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/postgres-mcp",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "mcpName": "io.github.YawLabs/postgres-mcp",
5
5
  "description": "PostgreSQL MCP server - query, schema introspection, explain, and health checks for AI assistants",
6
6
  "license": "MIT",