Skip to main content
Glama
YawLabs

@yawlabs/postgres-mcp

by YawLabs

I/O statistics and in-flight async I/O

pg_io_stats
Read-onlyIdempotent

Diagnose PostgreSQL I/O stalls by showing cumulative per-backend-type I/O stats and live in-flight async I/O, revealing which subsystem (client, autovacuum, checkpointer) uses which path.

Instructions

I/O observability: cumulative per-backend-type I/O from pg_stat_io (PostgreSQL 16+), plus in-flight asynchronous I/O handles from pg_aios (PostgreSQL 18+). This is the layer underneath pg_top_queries and pg_health -- it says WHICH subsystem is doing the I/O (client backends vs autovacuum vs checkpointer vs walwriter) and through which path, which a per-query or per-table view cannot.

  • io: one row per (backend_type, io_object, io_context) combination. Counters reads / writes / extends / writebacks / hits / evictions / reuses / fsyncs are bigints returned as decimal strings; read_time_ms / write_time_ms / writeback_time_ms / extend_time_ms / fsync_time_ms are float8 milliseconds. A timing of 0 next to a non-zero op count means track_io_timing is off, NOT that the I/O was free -- turn it on to get real numbers. A NULL counter means the operation is not possible for that combination, which is different from 0.

  • io[].read_bytes / write_bytes / extend_bytes: a normalized byte figure that means the same thing on every supported server. On PG16-17 it is computed as op_bytes * <op count>; on PG18 op_bytes was removed and the server reports bytes directly. The top-level byte_accounting field says which source produced the numbers.

  • io[].stats_reset: these are CUMULATIVE counters, so a row is only interpretable next to its reset point. Reported per row because that is how the view reports it; pg_stat_reset_shared('io') resets them together in practice, but this tool does not assert that.

  • Rows whose counters are all zero are omitted by default (pg_stat_io is mostly zeros on a quiet system, and the noise buries the handful of rows that matter). Pass includeZeroRows: true for the full matrix.

  • in_flight + io_method: PostgreSQL 18+ ONLY, and both keys are ABSENT on older servers rather than empty/null -- an empty in_flight array would read as 'nothing is stalled' when the truth is 'this server cannot tell you'. in_flight is live, currently-outstanding async I/O (pid, io_id, op, state, off, length, target_desc), which is what you want while a stall is happening rather than after it. io_method (worker / io_uring / sync) explains what in_flight can contain: with io_method = sync there is no asynchronous submission, so the array is legitimately empty no matter how much I/O is running. Requires PostgreSQL 16+. Sub-queries that fail (pg_stat_io and pg_aios are permission-gated on some managed providers) append to _warnings and set their field to null; the rest of the response still returns.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoMax rows per section (default 200). pg_stat_io has well under 200 combinations, so this effectively bounds the in-flight list on a busy PG18 server.
includeZeroRowsNoIf true, return every (backend_type, io_object, io_context) row including the ones with no recorded activity. Default false -- the view is mostly zeros on a quiet system.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
ioYesNull (not []) when the fetch was refused -- [] is a real answer on a freshly reset cluster.
_warningsNo
in_flightNoPostgreSQL 18+ only. Currently-outstanding async I/O. Null (not []) when the fetch was refused -- reading a denial as 'nothing outstanding' would point the investigation the wrong way.
io_methodNoPostgreSQL 18+ only. worker | io_uring | sync. With `sync` there is no async submission, so `in_flight` is legitimately empty however much I/O is running.
byte_accountingYesWhich source produced read_bytes / write_bytes / extend_bytes: native columns, or op_bytes * ops.
include_zero_rowsYesEchoed because it changes what an empty `io` means: no recorded I/O, vs the view returned nothing.
server_version_numYesEchoed so a caller can tell WHY the PG18-only keys are absent without a second round-trip.
Install Server

TDQS

A4.4/5.0
Behavior5/5

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

The description goes far beyond the readOnly/idempotent hints: it explains NULL vs 0 semantics, the meaning of 0 timing values with non-zero counts, cumulative counters and stats_reset, absent keys vs empty arrays on PG18, omitted zero rows, per-query sub-failures appending to _warnings, and permission gating. No contradiction with annotations.

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

Conciseness4/5

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

The description is long, but nearly every clause carries a non-obvious behavioral detail that is essential for correct interpretation (e.g., absent vs empty keys, timing=0 caveat, zero-row omission). It is structured with bullets between focused sections and front-loads the overall purpose before the details.

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

Completeness5/5

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

For a high-complexity PostgreSQL observability tool with an output schema available, the description covers version requirements, permission-gated failures, counter semantics, reset interpretation, zero-row filtering, and in-flight I/O caveats. An agent has enough information to call it correctly and interpret the result.

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% and both parameters are already documented with defaults and meaning. The description reinforces includeZeroRows and limit, but it adds little that is not already in the input schema; the baseline of 3 applies.

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 opens with 'I/O observability' and precisely defines the resource: cumulative per-backend-type I/O from pg_stat_io plus in-flight async I/O from pg_aios. It also differentiates itself from siblings by calling itself 'the layer underneath pg_top_queries and pg_health' and noting that per-query or per-table views cannot show the subsystem/path involved.

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

Usage Guidelines4/5

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

The description tells the agent when this tool is appropriate: when the question is which subsystem (client backends vs autovacuum vs checkpointer) and which I/O path is responsible, as opposed to per-query or per-table views. It also states required PostgreSQL versions and the includeZeroRows behavior for quiet systems, though it does not give explicit 'when not to use' alternatives beyond the sibling references.

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

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/YawLabs/postgres-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server