pgsteward
Provides read-only access to a fleet of PostgreSQL databases for LLM agents, enabling schema exploration, guarded SQL queries, execution plans, and database health checks without exposing credentials.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pgstewarddescribe the customer_order table on the staging connection"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
pgsteward
Read-only access to a fleet of PostgreSQL databases for LLM agents, over MCP. The agent picks a connection by id and never sees the credentials.
Claude, Cursor, opencode or any other MCP client can explore your schema, run queries, read execution plans and check database health from the chat.
Tools
Tool | What it does |
| Configured connections: id, read_only, environment. No network access unless |
| Databases on this connection's server. |
| Schemas in this connection's database (system schemas excluded). |
| Tables and views in a schema. |
| Columns, types, nullability, defaults, PK, FKs, indexes, row-count estimate. Errors if the relation does not exist. |
| Substring search for tables and columns across every non-system schema; reports truncation. |
| One guarded SQL statement, positional parameters, server-side row cap. |
|
|
| Eleven catalog checks; no extensions required, so it works on managed PostgreSQL. |
| Connection reachability. |
| Server version and current database. |
| Effective policy: read_only, DML/DDL, max_rows, max_bytes, query_timeout. |
Two more — describe_relationships and federated_lookup — join an entity
that lives in several databases under different keys. They are registered
only when a relationship map is configured, so they cost no context in a
session that has no such map.
Every tool returns a JSON string. describe_table, abridged:
{
"name": "customer_order", "schema": "public",
"columns": [
{"name": "id", "data_type": "bigint", "nullable": false, "is_primary_key": true,
"default": "nextval('customer_order_id_seq'::regclass)"},
{"name": "customer_id", "data_type": "bigint", "nullable": false,
"default": null, "is_primary_key": false},
{"name": "total", "data_type": "numeric(12,2)", "nullable": false,
"default": null, "is_primary_key": false}
],
"primary_key": ["id"],
"foreign_keys": [
{"column": "customer_id", "references_schema": "public",
"references_table": "customer", "references_column": "id",
"constraint_name": "customer_order_customer_id_fkey"}
],
"indexes": [
{"name": "idx_order_customer", "columns": ["customer_id"],
"is_unique": false, "included_columns": []}
],
"extra": {"estimated_row_count": 28431, "relation_kind": "table"},
"notes": []
}Response shapes, health-check thresholds and the privilege matrix: docs/tools.md.
Related MCP server: mcp-postgres
What this is for
pgsteward is built around one setup: an agent working with several PostgreSQL databases in a single session — staging and production, or several services. Four properties follow from that.
Read-only is enforced by PostgreSQL, not by the SQL classifier. Every
read runs inside BEGIN TRANSACTION READ ONLY, on top of
default_transaction_read_only and a server-side statement_timeout.
Statements that only look like reads — WITH ... DELETE ... RETURNING,
EXPLAIN ANALYZE INSERT — are rejected by the engine
(asserted against a live server).
Several connections, credentials on the server. The agent picks a
connection_id and never sees a DSN. Connection failures come back as a
stable code — auth_failed, database_not_found, unreachable — so the
host names, ports and role names in driver messages stay in the server log
instead of entering the model's context.
Health checks that refuse to guess. Under a least-privilege role
PostgreSQL blanks the columns these checks need instead of raising an
error, so a check that trusts the result reports ok having examined
nothing. pgsteward returns skipped and names the missing grant.
An audit log with no SQL in it. Every tool call logs the connection, statement class, duration, row count and outcome — failures included, since a refused write is worth as much to an audit as a successful read. The statement text and the parameter values are not written anywhere.
Install
With uv there is nothing to install ahead of
time: your MCP client can run uvx pgsteward directly.
uv tool install pgsteward # or: pipx install pgstewardRequires Python 3.11+ and a reachable PostgreSQL 14+. CI exercises 14 and 17 against a live server. 14 is the oldest release still supported upstream; older servers are likely to work, but nothing verifies that.
Quick start
1. Point pgsteward at a database. Configuration is entirely environment
variables — one line of metadata plus a block of credentials. Put them in
~/.config/pgsteward/.env, which pgsteward finds on its own:
mkdir -p ~/.config/pgsteward
touch ~/.config/pgsteward/.env && chmod 600 ~/.config/pgsteward/.envPGSTEWARD_DB_CONNECTIONS=web-shop:WEB_SHOP
WEB_SHOP_PG_HOST=127.0.0.1
WEB_SHOP_PG_PORT=5432
WEB_SHOP_PG_DATABASE=web_shop
WEB_SHOP_PG_USER=readonly_user
WEB_SHOP_PG_PASSWORD=secretweb-shop is the id the agent uses; WEB_SHOP is the prefix of the
credentials block. HOST, USER and DATABASE are required — none of
them is guessed. Read-only and write-forbidden are the defaults.
Leave WEB_SHOP_PG_PASSWORD empty and no password is sent at all, so a
Unix socket with peer, a TLS client certificate, .pgpass or an IAM
token work instead. See
docs/security.md.
2. Register it with your MCP client. For Claude Code:
claude mcp add pgsteward -- uvx pgstewardFor anything with a JSON config (Claude Desktop, Cursor, opencode, VS Code, Windsurf, Zed) the shape is the same, and carries no credentials:
{
"mcpServers": {
"pgsteward": {
"command": "uvx",
"args": ["pgsteward"]
}
}
}Exact file paths and per-client quirks: docs/integrations.md.
The variables can go in the client's env block instead of the .env, and
for a throwaway local database that is fine. For anything else the .env
is the safer of the two — see
docs/security.md.
3. Ask. "Which tables reference the customer id?", "Why is this query slow?", "Is anything wrong with this database right now?"
To try it without a real database, examples/quickstart brings up a seeded PostgreSQL in Docker with a ready-made config.
Security model
Reads are protected at three levels, and only the last two are guarantees:
Classification before execution. The statement is classified by its first significant keyword and checked against the policy; more than one statement per call is rejected. This is a filter: a keyword classifier can be fooled, so the guarantee rests on layer 2.
The transaction. Reads always execute inside
BEGIN TRANSACTION READ ONLY, whatever the connection flags say.The session. Read-only connections also set
default_transaction_read_only=on, and every connection sets a server-sidestatement_timeout.
Writes require both read_only=false on the connection and the matching
class enabled in policy. Both default to off.
Point it at a least-privilege role rather than a superuser. pgsteward does not rewrite the values it returns, so keeping a column — personal data, a secret — away from the agent is done with column-level grants or a view, and enforced by PostgreSQL: hiding columns from the agent.
How each layer is implemented and where it stops: docs/security.md. What pgsteward does not protect against, and how to deploy it safely: SECURITY.md.
Configuration
PGSTEWARD_DB_CONNECTIONS=web-shop:WEB_SHOP,analytics:ANALYTICSCSV of id:prefix. prefix defaults to the id uppercased, with dashes
and spaces turned into underscores. Credentials are then read from
<PREFIX>_PG_HOST / USER / DATABASE — all three required, unless
<PREFIX>_PG_DSN supplies the address whole — plus optional PORT,
PASSWORD, READ_ONLY, SSLMODE, QUERY_TIMEOUT, MAX_ROWS,
MAX_BYTES, POOL_MIN, POOL_MAX, ALLOW_DML, ALLOW_DDL.
An id ending in one of the suffixes you list in PGSTEWARD_ENV_SUFFIXES
(prod,staging, dev,uat — whichever your ids use) reports that
suffix as its environment in list_connections, so the agent can tell
production apart before it queries it. It is a label, not a guard — writes
are stopped by read_only and the policy, never by the name.
Full reference, including how .env is resolved when pgsteward is installed
from PyPI: docs/configuration.md.
Scope
PostgreSQL only, and that is a decision rather than a current state: the
health checks, the EXPLAIN (FORMAT JSON) parser and the READ ONLY
barrier the security model rests on are all PostgreSQL features with no
equivalent elsewhere. There is no engine field in the configuration and no
engine in the responses. The reasoning in full:
docs/architecture.md.
Transport is stdio. The MCP client starts pgsteward as a child process on demand: there is no service to deploy, and no SSE or HTTP endpoint either.
Not included, so that you can rule pgsteward out quickly: index
recommendations, pg_stat_statements workload analysis, and table or
index bloat estimates.
Development
git clone https://github.com/olegpydev/pgsteward && cd pgsteward
uv sync
uv run ruff check . && uv run ruff format --check .
uv run mypy pgsteward
uv run pytest -m "not integration"Integration tests need a throwaway PostgreSQL and are skipped without one; the command to start it is in CONTRIBUTING.md. What each suite is responsible for: docs/architecture.md.
Documentation
Document | Covers |
Every environment variable, | |
Response shapes, health-check thresholds, required privileges | |
How the three layers work, known gaps, hiding columns, audit log | |
Per-client config files and troubleshooting | |
Layout, request path, adapter boundary, testing strategy | |
Threat model and recommended deployment |
License
MIT — see LICENSE.
Available Tools
12 toolsanalyze_db_healthA
Eleven deterministic checks over the system catalog: connections, idle transactions, long queries, cache hit rate, invalid, unused and duplicate indexes, constraints, wraparound, sequences, replication. No extensions required. A check returns skipped, not ok, when the role lacks the privilege or the statistics window is too short to judge; overall_status is unknown when nothing could be checked.
| Name | Required | Description | Default |
|---|---|---|---|
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the behavioral burden and does so well: it discloses that the checks are deterministic and read-only in nature, that they rely on the system catalog and require no extensions, and it defines a non-obvious result semantic — skipped rather than ok when the role lacks privilege or the statistics window is short, and overall_status of unknown when nothing could be checked. That is real signal beyond the schema. It stops short of stating permission prerequisites or expected cost/latency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, all load-bearing: the capability and check inventory come first, the dependency constraint second, the result semantics last. The dense enumeration is the right format for eleven itemized checks, and no sentence restates the tool name or wastes a clause.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is a single-parameter read, and an output schema exists, so return structure need not be explained; the description wisely spends its space on the one thing the schema cannot convey — the skipped/unknown status semantics. The only remaining gap is the absence of guidance on when to reach for this tool over its siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter, connection_id, and its schema description already points to list_connections at 100% coverage. The description adds nothing about the parameter, but with full schema coverage the baseline of 3 applies. No compensating detail is needed here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ("Eleven deterministic checks over the system catalog") and enumerates the exact check families: connections, idle transactions, long queries, indexes, constraints, wraparound, sequences, replication. An agent knows instantly this is a health-assessment tool rather than a data-access tool. It doesn't name a sibling, but no sibling overlaps this capability, so the lack of explicit differentiation is minor.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the check list makes the health-diagnostic intent apparent, and "No extensions required" hints at a low-friction pre-diagnostic use case. There is no statement of when to call it versus the alternatives (query, explain_query, get_server_info) or of exclusion conditions. An agent can infer the use case but must guess the trigger.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_tableA
Describe one table or view: columns, primary key, foreign keys, indexes and an instant row-count estimate. Fails with an explicit error if the relation does not exist.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | Table name. | |
| schema | No | Schema name; defaults to "public". | |
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does reasonably well: it discloses the error contract ('fails with an explicit error if the relation does not exist') and flags that the row count is an 'instant estimate' rather than an exact count, which prevents misreading results. It does not mention permissions or that the operation is a pure read.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, with the output contents front-loaded and the failure mode appended as a secondary caveat. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no prose explanation, and the inputs are fully documented in the schema. The remaining gap is that, with no annotations present, the description never states this is a non-mutating read or what access it requires.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with defaults and a pointer to list_connections already documented, so the schema does the heavy lifting. The description only adds that the target may be a view, which is a small but real clarification.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb plus resource ('Describe one table or view') followed by an enumeration of exactly what is returned (columns, primary key, foreign keys, indexes, row-count estimate). This clearly separates it from list_tables and search_schema, though it never names those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit 'use this when...' statement or exclusion of alternatives; usage is only implied by the word 'one' versus the collection-oriented siblings. An agent can infer the intent (inspect a single relation's structure) but must reason about it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_queryA
Execution plan via EXPLAIN (FORMAT JSON), parsed into a tree with warnings for sequential scans and stale statistics. analyze=true physically executes the statement to get actual row counts and timings; without it there are planner estimates and no timings.
| Name | Required | Description | Default |
|---|---|---|---|
| params | No | Positional PostgreSQL parameters ($1, $2, ...). | |
| analyze | No | Run EXPLAIN ANALYZE, executing the statement. | |
| statement | Yes | SQL statement to analyze. | |
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full burden and does disclose the most consequential behavior: analyze=true physically executes the statement, and the plan is post-processed into a tree with sequential-scan and stale-statistics warnings. It stops short of stating that executing a DML statement under analyze=true mutates data, or what permissions the connection needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, and the core output shape is front-loaded before the mode tradeoff. Every clause conveys information an agent could act on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be spelled out, and the description still characterizes them (parsed tree plus warnings). Combined with fully documented parameters, an agent has enough to invoke this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, and the description earns more by clarifying what `analyze` changes in the output: actual row counts and timings versus planner estimates with no timings. `params` and `connection_id` are left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: it produces an execution plan via EXPLAIN (FORMAT JSON) parsed into a tree with warnings. That is far more precise than a generic 'explain' label. It never names the sibling `query` tool, so the agent must infer the boundary between running a statement and planning one.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear guidance on choosing between the two modes (analyze=true executes, false uses planner estimates), which is useful. It gives no guidance on when to pick this tool over `query` or `analyze_db_health`, and no prerequisites such as required connection state or read-only expectations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_security_configA
Effective policy of a connection: read_only, whether DML and DDL are allowed, max_rows, max_bytes and query_timeout. Check it before attempting a write.
| Name | Required | Description | Default |
|---|---|---|---|
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full disclosure burden. It usefully signals that the policy is 'effective' (i.e., resolved/merged rather than raw per-connection rows) and lists the limits a caller can rely on, which is real added value. It does not say what happens on an unknown or unauthorized connection, nor whether the read itself is scoped or rate-limited.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single dense sentence plus a short imperative; both clauses earn their place and the returned fields are front-loaded. The fragmentary opening ('Effective policy of a connection:') costs a little polish but not clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no prose, and the single required parameter is fully documented in the schema. What remains to be desired is failure-mode behavior, but for a simple read of a config with one param, the definition is essentially call-ready.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
One parameter with 100% schema description coverage including a pointer to list_connections, so the schema already does the work. The description adds no syntax, format, or defaults beyond 'of a connection', making baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names the resource (a connection's effective security policy) and enumerates the exact fields returned: read_only, DML/DDL permissions, max_rows, max_bytes, query_timeout. That is specific and distinguishable from list/query siblings, though it opens with a noun phrase rather than a verb, so the 'get/read' framing must be inferred.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a concrete triggering condition: 'Check it before attempting a write.' That is real when-to-use guidance tied to a workflow. It stops short of naming alternatives or stating when the check can be skipped, so it is clear context rather than full routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_server_infoC
Server version and current database behind a connection.
| Name | Required | Description | Default |
|---|---|---|---|
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It implies a read-only metadata lookup scoped to a single connection, which is useful, but it does not state whether an invalid connection errors, what the version format is, or anything about latency/caching.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One short sentence with no padding, front-loading the two returned values. It is efficient, though slightly terse for a tool with no annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the sole parameter is fully documented. Still, for a tool with zero annotations the description could say more about read-only behavior and connection requirements.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single connection_id parameter is documented in the schema with a pointer to list_connections. The description adds no further parameter detail, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names two specific outputs (server version, current database) tied to a connection, which is more than a bare restatement of the name. However, it doesn't distinguish it from siblings like ping or list_databases, which an agent could easily confuse with it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use or when-not-to-use guidance. The agent must infer that this is for inspecting connection/server metadata rather than data operations, and the description does not point to ping or list_databases as alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_connectionsA
List the configured connections: id, read_only and inferred environment. Start here; every other tool needs a connection_id. Set probe=true to also test reachability, which opens a connection to each database.
| Name | Required | Description | Default |
|---|---|---|---|
| probe | No | Test reachability of every connection (default false: no network access, alive is null). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It discloses the important side effect that probe=true opens a connection to each database, implying that the default listing does not. It does not mention authentication or permission requirements, which leaves a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what is returned, then the prerequisite, then the optional probe behavior. No sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter listing tool with an output schema, the description covers what is returned, the prerequisite for sibling tools, and the one optional behavioral mode. Nothing an agent needs in order to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents the probe parameter, its default, and the alive-is-null behavior. The description adds only the phrase that probing opens a connection to each database, which is useful but largely overlaps the schema's 'test reachability' wording.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('List the configured connections') and names the returned fields (id, read_only, inferred environment). It also distinguishes its role from all sibling tools by declaring that every other tool needs a connection_id, which no other tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit sequencing guidance ('Start here; every other tool needs a connection_id') and explains the optional probe mode. Alternatives are not named, but the prerequisite makes the ordering unambiguous; it does not state when not to use the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_databasesA
List the databases on this connection's server. Querying one needs its own configured connection: PostgreSQL cannot read across databases in a session.
| Name | Required | Description | Default |
|---|---|---|---|
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry behavioral context, and it discloses the key PostgreSQL limitation that cross-database access requires separate connections. It does not cover read-only safety, permissions, or pagination, but it surfaces the most important non-obvious constraint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two tightly written sentences with the purpose front-loaded and the caveat immediately following. Every sentence contributes useful information with no waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter list operation with full schema coverage and an output schema, the description supplies the only significant non-obvious caveat about PostgreSQL cross-database connections. Nothing else is needed for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the sole connection_id parameter is fully documented in the schema. The description adds no additional parameter semantics beyond what the schema already provides, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource, "List the databases," and scopes it to "this connection's server." This clearly distinguishes it from sibling tools such as list_schemas and list_tables.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operational context by explaining that querying a database requires its own configured connection, since PostgreSQL cannot read across databases in a session. It does not explicitly name alternatives or when-not to use this tool, so it falls short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_schemasA
List the non-system schemas in this connection's database.
| Name | Required | Description | Default |
|---|---|---|---|
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral load; 'List' plus 'non-system' conveys a read-only, filtered operation and excludes system schemas, which is useful context. However, nothing is said about pagination, volume, or permissions, so the disclosure is thin for a no-annotation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One tightly scoped sentence with no filler, and the key qualifiers (non-system, connection-scoped) are front-loaded. It could only be improved by adding routing guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter read tool with full schema coverage and an output schema covering return values, the description is essentially complete. Only sibling routing and pagination hints are missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single connection_id parameter is documented with a pointer to list_connections. The description adds no parameter-level detail beyond the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (List) plus resource (schemas) plus scope qualifiers (non-system, this connection's database). It distinguishes itself from list_databases and list_tables by naming the schema resource, though it does not explicitly contrast with search_schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied by the tool hierarchy (connection → database → schemas → tables); there is no explicit statement of when to prefer this over search_schema or describe_table. No when-not conditions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tablesB
List tables and views in a schema (default "public").
| Name | Required | Description | Default |
|---|---|---|---|
| schema | No | Schema name; defaults to "public". | |
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description must carry the full behavioral burden. It implies a read-only listing and scopes it to one schema, but says nothing about permissions, pagination, or whether system tables are included, and mention of views is the only added nuance.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no padding, and the default is placed in parentheses where it belongs. It is efficient, though terse enough that it leaves obvious questions unanswered.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists and both parameters are fully documented, so for a simple read-only listing the description covers what an agent needs to invoke it. Only the absence of any permission or scope caveats keeps it from being complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both 'schema' and 'connection_id' documented in the schema itself. The description only restates the default of "public", adding nothing beyond structured fields, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb (list) and resource (tables and views), which cleanly separates it from list_databases, list_schemas and describe_table. It is clear but never explicitly contrasts itself with those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to use this versus list_schemas or describe_table, nor any prerequisite such as calling list_connections first. The connection_id link to list_connections lives in the schema, not the description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pingA
Check that a connection is reachable (SELECT 1).
| Name | Required | Description | Default |
|---|---|---|---|
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose that a trivial SELECT 1 is executed, which signals a cheap, non-mutating read, but it says nothing about whether a failure throws an error or returns a false result, nor about cost/timeout behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with the action first and the implementation detail in parentheses; nothing is wasted and nothing important is buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and for a one-parameter probe this is nearly sufficient. The remaining gap is failure semantics — whether an unreachable connection raises or returns a negative result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single connection_id parameter is documented there with a pointer to list_connections, so the description adds nothing beyond it. Baseline 3 applies since the schema does all the parameter work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Check that a connection is reachable') and even names the mechanism (SELECT 1), so an agent can tell it apart from query or analyze_db_health. It stops short of explicitly naming the sibling it replaces, but the intent is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the check is a precondition-style probe, but the description never says when to prefer it over analyze_db_health or get_server_info, nor when not to bother. An agent can infer the case but must do the work itself.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryA
Run a single SQL statement. Read-only by default; writes need the connection policy to allow them. Use params for positional parameters ($1) rather than string interpolation. Rows are capped by min(limit, the connection max_rows): applied_limit is the cap that was used and truncated says rows were dropped. When applied_limit is below the limit you asked for, max_rows cut the result and the answer is incomplete. A separate cap on response size can also cut it; when it does, notes says so and the fix is fewer columns, not fewer rows.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return. | |
| params | No | Positional PostgreSQL parameters ($1, $2, ...). | |
| statement | Yes | A single SQL statement. | |
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: read-only by default, writes gated by connection policy, row caps as min(limit, max_rows), and a distinct response-size cap. It doesn't cover transaction behavior, DDL permissibility, or timeouts, so it stops short of fully describing execution semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then proceeds in priority order: safety model, parameter binding, then truncation semantics. Dense but every sentence carries operational meaning; the closing sentence on the size cap is the only one that could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-field naming needn't be explained, yet the description still tells the agent how to act on applied_limit, truncated, and notes — the practically important part. What's missing is execution context such as statement-type restrictions or timeout behavior for a tool whose whole job is arbitrary SQL execution.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds genuine meaning for limit by defining the effective cap as min(limit, connection max_rows) and explaining the applied_limit/truncated interaction, but connection_id and statement get no elaboration beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'Run a single SQL statement,' which cleanly separates it from schema-inspection siblings like list_tables or describe_table. It doesn't explicitly name explain_query as the non-executing alternative, so the boundary with that sibling is left implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real usage guidance on parameter binding ('use params for positional parameters ($1) rather than string interpolation') and on interpreting truncation. But it never states when to prefer this over explain_query or the list_* discovery tools, and no when-not-to-use condition is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_schemaA
Find tables and columns whose name contains a substring, across every non-system schema. Use it when you know the field you need but not which table holds it. Note that "_" and "%" are wildcards.
| Name | Required | Description | Default |
|---|---|---|---|
| schema | No | Restrict the search to one schema. | |
| pattern | Yes | Substring to look for in table and column names. | |
| connection_id | Yes | Connection id. See list_connections. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses the non-system-schema exclusion and the wildcard behavior of '_' and '%', but omits case sensitivity, matching limits, and result-size behavior for what could be a broad sweep.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what it does, then when to use it, then the one non-obvious caveat. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Three fully documented parameters plus an output schema mean return values need no explanation; scope and wildcard semantics are covered. Only case sensitivity and result limits remain unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds genuine value by warning that '_' and '%' in the pattern act as wildcards, which the schema does not state. The optional schema restriction is left to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (find) and resource (tables and columns) with explicit scope: 'across every non-system schema.' This separates it from list_tables/describe_table by implication, though no sibling is named directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use it when you know the field you need but not which table holds it' gives a clear selection context. It lacks explicit when-not guidance or a named alternative (e.g., list_tables) to complete the routing story.
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.
12 tool updates
v0.1.0- First observed
analyze_db_health - First observed
describe_table - First observed
explain_query - First observed
get_security_config - First observed
get_server_info - First observed
list_connections - First observed
list_databases - First observed
list_schemas - First observed
list_tables - First observed
ping - First observed
query - First observed
search_schema
TDQS
Scored across 12 tools
Each tool maps to a distinct level of PostgreSQL hierarchy (connection → database → schema → table) or a distinct action (query, explain, health analysis), so selection is straightforward. Minor overlaps exist: ping largely duplicates list_connections with probe=true, and get_server_info overlaps slightly with list_databases, but descriptions clarify the intended use.
Names are uniformly snake_case and mostly follow a verb_noun pattern (list_tables, describe_table, analyze_db_health). Two bare verbs (ping, query) are the only deviations and are conventional enough to remain predictable.
Twelve tools is well-scoped for a PostgreSQL introspection and stewardship server; each earns its place across discovery, execution, planning, health, and policy concerns. No obvious redundancy that should be merged.
The surface covers the full exploration lifecycle plus query execution, EXPLAIN, health checks, and policy inspection, with writes handled via query under policy. Minor gaps remain: no session/cancel tool, no standalone index or role/privilege listing, and no extension enumeration, though these are largely reachable through query.
Maintenance
Related MCP Connectors
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
Deterministic safety, correctness & cost gate that vets Postgres SQL before your AI agent runs it.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with PostgreSQL databases through both HTTP and stdio transports. Supports executing read-only SQL queries, listing tables, and retrieving schema information with stateful session management.45 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to execute SQL queries and introspect PostgreSQL schemas, tables, and indexes with read-only safety by default. Supports optional write operations and works with Claude, LangChain, and other agents via stdio or HTTP transports.-
- AlicenseNot gradedqualityCmaintenanceEnables read-only, SELECT-only querying of any Postgres database through MCP-compatible clients like Claude, with schema introspection and guarded SQL execution.MIT
- FlicenseNot gradedqualityCmaintenanceEnables LLM agents to explore a Postgres database and answer questions by running safe, read-only SQL queries through MCP tools.-