Skip to main content
Glama
PlbKin190

postgres-mcp-lab

by PlbKin190

postgres-mcp-lab

A stdio MCP server that gives Claude Code read-only access to a real PostgreSQL database: relational queries, catalog inspection, execution plans, vector similarity and graph traversal. A database enforces relationships, uses indexes and explains its work; a flat file cannot provide the same execution model.

The repository contains six generic tools and an invented public-library dataset. No embedding account or API key is needed for the default demo. Claude Code requires its usual authentication and connectivity.

Quickstart

Requirements: Docker with Compose v2, Git, and enough disk space to compile a PostgreSQL extension. From the repository root:

cp .env.example .env
docker compose up

The first build downloads dependencies and compiles Apache AGE; allow several minutes. Leave the terminal open. Initialization runs automatically on an empty volume. The MCP container has no HTTP endpoint: it waits for a client on standard input/output.

Database image

db/Dockerfile starts from pgvector/pgvector:pg16 and compiles AGE from its release/PG16/1.5.0 release branch. This avoids attempting package installation from an init SQL script. AGE is preloaded in every backend, so the restricted role does not need permission to execute LOAD. The build argument AGE_REF can select an audited compatible revision.

The three SQL files are copied into the inherited docker-entrypoint-initdb.d directory at image build time. The PostgreSQL entrypoint executes them in filename order. This baked-in alternative to a bind mount needs no host-specific path. Rebuild the image after editing init files.

Initialization is not a migration system: it only runs on an empty database volume. The base image provides an anonymous data volume. docker compose down --volumes destroys the demo database; the next start initializes it again. Build tools remain in the database image for simplicity. The health check uses TCP and the reader role so it waits for the final database server, not the temporary initialization server.

Related MCP server: @yawlabs/postgres-mcp

Connect Claude Code

In a second terminal, register the server from the repository root:

claude mcp add --transport stdio --scope project postgres-lab -- docker compose --project-directory . run --rm -T --no-deps mcp

Alternatively, merge examples/claude_code_mcp.json into the project MCP configuration. Start Claude Code from this repository so that the relative Compose directory resolves correctly. Keep the database running before connecting.

docker compose run creates a separate stdio process for each MCP client; it does not attach to the idle MCP container started by up. Never use docker compose up as the stdio command: its service logs would corrupt the protocol. Only MCP messages go to stdout; generic diagnostics go to stderr.

Architecture

See docs/architecture.md for the component diagram, the five-layer read-only chain, and the entity diagram of the demo dataset.

Tools

All tools return JSON text. Failures return MCP isError: true. Vector and graph identifiers must be simple ASCII names of at most 63 characters.

Tool

Parameters

Behavior

query

sql, params=[], limit?, timeout_ms?

One SELECT or read-only WITH, positional scalar parameters, rows, column types and truncation flag. No trailing semicolon.

schema

kind: schemas, tables, columns, indexes or foreign_keys; schema?, table?, limit?

Catalog inspection, one kind per call. Filter by schema to avoid catalog noise; omit table for schemas.

explain

sql, params=[], timeout_ms?

JSON plan of the original query without ANALYZE.

semantic

schema, table, vector_column, columns (1–20 names), text, k=5

pgvector cosine nearest neighbors; includes similarity and provider metadata.

cypher

graph, query, columns (names in RETURN order), limit?, timeout_ms?

Read-only AGE traversal with an explicit output signature.

health

none

Connection status, PostgreSQL version, read-only settings, timeout and vector/AGE versions.

limit and k cannot exceed MAX_ROWS; timeout_ms can only lower the configured timeout. SQL parameter values are strings, finite numbers, booleans or null. Cast JSON strings inside SQL when needed. AGE values retain their textual representation rather than undergoing guessed JSON conversion.

Two-minute demonstration

Ask these five questions in Claude Code and permit the read-only calls:

  1. “Check the connection and extensions. Inspect the demo schema, including columns, indexes and foreign keys.” health verifies the connection; schema runs once per kind. Expect read-only settings on, vector and AGE versions, two relational tables, a foreign key and an HNSW index.

  2. “How many available copies are on each shelf? Use a parameterized query to include shelves with at least three copies.” query joins demo.shelves and demo.books, groups by shelf and binds the threshold as $1. Totals are 10, 7 and 4.

  3. “Explain the plan for finding books on shelf 1 without executing the query. Is an index necessarily useful on ten rows?” explain plans a SELECT with params: [1]. A sequential scan is reasonable for this tiny dataset; an index is not guaranteed to be chosen.

  4. “Use vector search on demo.books for the three closest descriptions to ‘forest trees nature’. Return id, title and description, using embedding as the vector column.” semantic hashes the query into 64 dimensions and orders by pgvector cosine distance. Forest-related books should rank near the top. This is token overlap, not language understanding.

  5. “In the reading graph, which books point to the Forest topic through ABOUT? Return their titles using Cypher.” cypher traverses the graph. Expect The Moss Compass, Small Wings at Dusk and Seeds Under Glass; order is unspecified.

A concrete graph call:

{
  "graph": "reading",
  "query": "MATCH (b:Book)-[:ABOUT]->(t:Topic) WHERE t.name = 'Forest' RETURN b.title",
  "columns": ["title"],
  "limit": 10
}

The seed contains ten invented books, three shelves, three topics and ABOUT/RELATED_TO edges. Graph book IDs match relational IDs. No real people or records are represented.

Embeddings

EMBEDDING_PROVIDER=hash lowercases ASCII tokens, computes a polynomial hash modulo 2147483647, projects token counts into N buckets and L2-normalizes the vector. src/embedding.ts and demo.hash_embedding implement the same specification. Seed vectors encode description only, in 64 dimensions. Floating-point storage differences are expected.

This is a deterministic demonstration encoder, not a semantic model. It has collisions, no synonym understanding and no multilingual representations. Non-ASCII characters act as token separators; empty token input is rejected. After dependencies and images are downloaded, the hash encoder and database require no network access or API key.

For a real provider:

  1. Set EMBEDDING_PROVIDER=openai, OPENAI_API_KEY, OPENAI_EMBEDDING_MODEL, OPENAI_EMBEDDING_URL and EMBEDDING_DIMENSIONS in your private environment.

  2. Use a separate privileged ingestion process to regenerate all stored vectors with the same provider, model, input convention and dimensions. Change the column dimension and rebuild its index if necessary.

  3. Point semantic at that table. This server intentionally provides no ingestion or write tool.

Never compare OpenAI query vectors to the seed hash vectors, even when dimensions match. The endpoint must support the OpenAI embeddings request shape, including dimensions. HTTPS is required and redirects are refused. Query text leaves the machine with this provider; table vectors and rows are not sent by the embedding module.

Configuration

All runtime configuration is environmental; see .env.example. Compose loads .env for the MCP service. Native Node processes require exported variables or --env-file.

Variables

Default / purpose

PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD

db, 5432, library, reader, empty password; separate fields, no database URL.

PGSSL, PGSSL_CA

disable for the isolated demo; verify-full for verified TLS, optional PEM CA content.

POOL_MAX, CONNECT_TIMEOUT_MS

4 connections, 5000 ms.

STATEMENT_TIMEOUT_MS

5000 ms; configurable range 100–30000.

MAX_ROWS, MAX_RESPONSE_BYTES

100 rows (configurable maximum 1000), 65536 bytes.

EMBEDDING_PROVIDER, EMBEDDING_DIMENSIONS

hash, 64; dimensions 8–2000.

EMBEDDING_TIMEOUT_MS

10000 ms.

OPENAI_API_KEY, OPENAI_EMBEDDING_URL, OPENAI_EMBEDDING_MODEL

Empty key, public embeddings endpoint, text-embedding-3-small.

For another database, configure a separately provisioned least-privileged role. query, schema, explain and health work without extensions; absent extension versions are null. Vector search currently expects pgvector in public. AGE must already be loaded in each connection, for example by administrator-configured preloading.

Security

The safeguards are visible in src/guard.ts, src/db.ts and the initialization SQL:

  • Every pool connection starts with default_transaction_read_only=on, statement and idle-transaction timeouts, a fixed search path and standard-conforming strings.

  • Every operation uses BEGIN TRANSACTION READ ONLY and always rolls back. Failed rollback destroys the connection.

  • Conservative lexical guards reject write keywords, comments, semicolons, multiple statements, backslashes, dollar quoting and selected privileged functions. SQL must start with SELECT/WITH; Cypher must use read-oriented clauses. Bind SQL values rather than embedding literals.

  • Parameter values are bound; identifiers are validated and quoted. AGE requires literal query text: it is validated and single quotes are escaped. Explicit output columns avoid fragile RETURN parsing.

  • An outer row limit cannot be bypassed by an inner LIMIT or CTE. One additional row detects truncation. Oversized serialized tool payloads are rejected, reserving space for the MCP envelope. Explain returns one plan document subject to the response-size budget.

  • Raw database/network/provider errors and environment values are never forwarded. There is no database-backed telemetry or connection-string output.

  • The reader is not a superuser or owner, has no role memberships, TEMP or CREATE rights, and only SELECT on demo and graph tables. AGE graph DDL helpers are not executable by the reader; traversal still requires extension function execution privileges.

These are defense-in-depth controls, not a sandbox for arbitrary hostile SQL. PostgreSQL read-only mode does not prevent every effect of user-defined functions, extensions, network calls, advisory locks or resource consumption. Audit executable routines, SECURITY DEFINER functions, extension permissions and role memberships before connecting any non-demo database. Never use superuser credentials. MCP read-only annotations are descriptive, not enforcement.

The demo uses passwordless trust authentication to avoid shipping credentials. Its database network is internal, with no published database port. Anyone controlling Docker or another container on that network can impersonate the bootstrap role. This is for a disposable local demo, not a shared host or production deployment. Use SCRAM, network policy, verified TLS and an independently provisioned reader elsewhere.

Read-only access can disclose everything the role can read. Limit grants and review results before sharing them. Treat database text as untrusted data, never as instructions to Claude.

Development and verification

npm install
npm run build
npm test

Node.js 22 is required. npm run dev uses tsx and exported variables. For native execution with an environment file:

node --env-file=.env dist/index.js

The hostname db resolves inside Compose, not from the host shell. Configure a reachable database for native development.

test/guards.test.ts exercises lexical rejection, escaping and the hash specification. test/database.test.ts is an opt-in integration suite: export TEST_DATABASE=1 and connection variables for a freshly seeded demo database, then run npm test. It checks all six tools, encoder parity, row limits, response limits and timeout recovery. It assumes hash/64 and the default response budget. Without the opt-in, this suite is skipped.

Before publishing, run a clean Docker build, the integration suite and all five Claude prompts. Independently inspect privileges and confirm that direct INSERT as reader fails, not merely the MCP guard. Test write CTEs, multiple statements, Cypher CREATE and attempts to change transaction settings. Record versions and results.

No build or integration run is claimed here. Generate and commit a real npm lockfile after verification, then use npm ci in Docker. Pin image digests and the AGE commit for reproducible releases; current branches, tags and npm ranges are not immutable.

Limits

  • Stdio only: no HTTP service, remote authentication layer or migrations.

  • Lexical guards are not complete SQL/Cypher parsers and may reject harmless words in literals or identifiers. Unusual quoted identifiers are unsupported in vector/graph arguments.

  • Row and response limits bound delivery, not peak memory or database work. Large fields and aggregates may be materialized before rejection; apply database resource controls to untrusted workloads.

  • Timeouts apply per statement, not as a total tool deadline. Embedding requests have a separate deadline.

  • PostgreSQL catalog visibility can exceed table-data visibility. AGE compatibility and permissions need testing against the selected versions and CPU architecture.

  • HNSW is approximate; ten rows do not demonstrate index performance. Ingestion and reindexing remain administrative operations.

License

Apache License 2.0. Copyright 2026 Christian Verbrugge. See LICENSE and NOTICE. Dependencies and database images retain their own licenses.

Available Tools

6 tools
cypherA
Read-onlyIdempotent

Run read-only Apache AGE Cypher. Supply graph and explicit output column names.

ParametersJSON Schema
NameRequiredDescriptionDefault
graphYes
limitNo
queryYes
columnsYesOutput names in RETURN order; count must match RETURN expressions.
timeout_msNo

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already indicate readOnlyHint=true and destructiveHint=false, so the description's 'read-only' aligns but adds no contradiction. The description adds context about needing graph and explicit columns, which are behavioral requirements. It doesn't repeat the annotations, and provides useful constraint about output columns.

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

Conciseness5/5

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

The description is a single sentence that is front-loaded with the core purpose ('Run read-only Apache AGE Cypher') followed by essential requirements. Every word earns its place; no fluff or redundant information.

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

Completeness3/5

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

Given the tool's complexity (Cypher queries) and the absence of an output schema, the description provides the basics but lacks details on return format, error handling, or the relationship between 'columns' and the query's RETURN clause. The schema partially covers constraints, but the description could elaborate on how 'columns' must match the query's return expressions, which is only partially in the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 20%, so the description must compensate. The description mentions 'graph' and 'explicit output column names' which adds meaning to the 'graph' and 'columns' parameters. It doesn't detail 'query' or 'limit', but the schema itself provides structural constraints. The description helps clarify the critical 'columns' parameter by stating they are explicit output names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool executes read-only Apache AGE Cypher queries, which distinguishes it from a general query tool. However, it does not explicitly differentiate from siblings like 'query' or 'semantic', leaving some ambiguity.

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

Usage Guidelines3/5

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

The description implies when to use this tool (for Cypher on Apache AGE) but does not provide explicit guidance on when not to use it or which sibling tools might be better alternatives. For example, it doesn't mention that 'query' might be for SQL or that 'explain' is for execution plans.

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

explainA
Read-onlyIdempotent

Return a JSON execution plan without ANALYZE; the query is not executed.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYesOne SELECT or read-only WITH statement; no trailing semicolon.
paramsNo
timeout_msNo

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already provide readOnlyHint, idempotentHint, and destructiveHint. The description adds meaningful nuance beyond those annotations by clarifying that the query is not actually executed and that the output is a JSON execution plan. This is valuable given no output schema is present, and there is no contradiction with the annotations.

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

Conciseness5/5

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

The description is a single, front-loaded sentence with no wasted words. It states the core behavior first and then clarifies the critical caveat that the query is not executed.

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

Completeness4/5

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

For a simple explain-style tool, the description plus annotations cover the safety profile and the output format. The main missing piece is guidance on params and timeout_ms, but the core behavior is fully specified and the schema covers sql constraints.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool description says nothing about sql, params, or timeout_ms. Schema description coverage is only 33% (sql has a description, but params and timeout_ms do not), and the description does not compensate for that gap, leaving parameter semantics under-specified.

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 states a specific verb and resource: it returns a JSON execution plan without ANALYZE. The explicit 'query is not executed' clearly distinguishes this from the sibling query tool, so there is no ambiguity about what the tool does.

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

Usage Guidelines3/5

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

The description implies that this tool is for planning rather than executing, and that query should be used when results are needed. However, it never explicitly names alternatives or states when not to use this tool, so usage guidance is only implied rather than direct.

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

healthA
Read-onlyIdempotent

Check PostgreSQL connectivity, read-only settings and installed vector/age versions.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds useful context about what the health check covers (connectivity, read-only settings, vector/age versions), which goes beyond the annotations. However, it doesn't disclose details like whether it returns a summary object or detailed diagnostics, but that's minor for a health check.

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

Conciseness5/5

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

The description is a single, concise sentence that front-loads the main purpose and lists the specific checks. Every word earns its place, and there is no redundancy or filler.

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

Completeness4/5

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

For a zero-parameter, read-only health check tool, the description is complete. It tells the agent what the tool checks (connectivity, read-only settings, versions), and the annotations cover the safety profile. The only minor gap is that it doesn't describe the return format, but with no output schema and a simple health check, this is acceptable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema provides no parameter documentation. The description compensates by explaining what the tool checks, which is sufficient for an agent to understand what the tool does without needing parameter details. Baseline 4 is appropriate for a zero-parameter tool.

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 clearly states the tool's purpose: checking PostgreSQL connectivity, read-only settings, and installed vector/age versions. It uses specific verbs and resources, and it is distinct from sibling tools like query, schema, explain, semantic, and cypher, which all perform different operations.

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 implies when to use this tool: when you need to verify database health, connectivity, read-only status, or installed extensions. It doesn't explicitly state when not to use it or name alternatives, but the context is clear enough for an agent to select it appropriately.

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

queryA
Read-onlyIdempotent

Run a parameterized read-only SELECT with server-enforced row and time limits.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYesOne SELECT or read-only WITH statement; no trailing semicolon.
limitNo
paramsNo
timeout_msNo

TDQS

A3.8/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, and the description is consistent with them. It adds valuable behavioral context: queries are parameterized and subject to server-enforced row and time limits. 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.

Conciseness5/5

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

A single compact sentence communicates the core operation, parameterization, safety, and limits. Every phrase carries meaning, and the most important constraints are front-loaded without unnecessary detail.

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

Completeness4/5

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

For a query tool with 4 parameters, the description plus schema and annotations cover the read-only nature, parameterization, and limits. It does not describe the result shape, but with no output schema and the expectation of query rows, this is a minor gap rather than a blocking omission.

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 description coverage is only 25%, so the description must compensate. 'Parameterized' gives meaning to the params array, and 'row and time limits' maps to limit and timeout_ms. However, it does not explain placeholder syntax, how params bind to the SQL, or the exact behavior when limits are exceeded.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear action ('Run') on a SQL SELECT resource, with the key restrictions 'parameterized' and 'read-only'. It distinguishes the tool from a generic query runner, but it does not explicitly contrast it with sibling tools like 'cypher' or 'schema'.

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

Usage Guidelines3/5

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

The read-only SELECT wording implies when the tool should be used: for safe SQL read queries, not for writes or other operations. However, it does not explicitly explain when to prefer this tool over siblings like 'cypher' or 'explain', leaving some selection guidance to inference.

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

schemaC
Read-onlyIdempotent

Inspect schemas, tables, columns, indexes or foreign keys. Repeat for each kind.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindYes
limitNo
tableNo
schemaNo

TDQS

C2.9/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds a useful behavioral note about repeating calls for each kind, but it does not disclose what 'inspect' returns or how results are shaped. 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 very short and front-loaded, with no filler words. The 'Repeat for each kind' instruction is a bit cryptic, but overall the text is efficient and easy to scan.

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

Completeness2/5

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

With no output schema and minimal parameter documentation, the description does not fully equip an agent to call the tool correctly across all kinds. It fails to explain parameter relationships, return behavior, or how the optional filter parameters apply to each kind.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, but it only restates the kind enum and says nothing about limit, table, or schema parameters. For example, it does not explain that inspecting columns likely requires table/schema context. This leaves most parameter semantics to inference.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Inspect') and explicitly enumerates the resources it operates on: schemas, tables, columns, indexes, and foreign keys. This makes the tool's scope reasonably clear, though it does not differentiate it from siblings like query or explain beyond the metadata focus.

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

Usage Guidelines2/5

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

No guidance is given about when to use this tool versus query, explain, semantic, or cypher. The phrase 'Repeat for each kind' hints at a multi-call pattern, but it does not clarify the conditions under which this tool should be selected or excluded.

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

semanticA
Read-onlyIdempotent

Rank rows using pgvector cosine distance. Default hash encoding measures token overlap, not meaning.

ParametersJSON Schema
NameRequiredDescriptionDefault
kNo
textYes
tableYes
schemaYes
columnsYes
vector_columnYes

TDQS

A3.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds valuable behavioral context beyond annotations: it uses cosine distance and warns that the default encoding may not actually capture meaning despite the 'semantic' name. This is important for setting correct expectations.

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

Conciseness5/5

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

Two sentences, front-loaded with the core purpose, followed by an important caveat. There is no fluff or repetition of schema/annotation information; every sentence earns its place.

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

Completeness2/5

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

For a tool with 6 parameters, 5 required, no output schema, and zero schema description coverage, the description is too sparse. It does not explain how parameters interact, what output the agent should expect, or how to construct a valid call. Annotations cover safety but not invocation completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description provides no meaning for any of the 6 parameters (schema, table, vector_column, columns, text, k). With low schema coverage, the description carries the full burden for parameter semantics, and it fails to do so.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Rank') and resource ('rows'), and identifies the mechanism (pgvector cosine distance). It clearly signals a semantic search/ranking tool, which distinguishes it from sibling tools like query, though it does not explicitly name sibling alternatives.

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 provides clear context: this tool ranks by semantic similarity, with the caveat that default hash encoding measures token overlap rather than meaning. It implies when to use it (meaning-based ranking) but does not explicitly state when not to use it or name the alternative tool.

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.

  1. 6 tool updatesv1.0.0
    • First observedcypher
    • First observedexplain
    • First observedhealth
    • First observedquery
    • First observedschema
    • First observedsemantic

TDQS

A3.8/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a clearly distinct operation: generic SQL, schema inspection, query planning, vector similarity, Cypher graph queries, and health checks. There is little risk of selecting the wrong tool for a given task.

Naming Consistency4/5

All tool names are single lowercase words, giving a clean and consistent style. However, they mix verbs and nouns (query/explain vs schema/health) rather than following a strict verb_noun pattern.

Tool Count5/5

Six tools is well-scoped for a PostgreSQL lab server covering SQL, schema, plans, vector search, graph queries, and health. Each tool earns its place without redundancy.

Completeness5/5

The read-only domain is fully covered: arbitrary SQL, schema inspection, execution plans, vector ranking, graph querying, and environment health. No obvious dead ends or missing core operations for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides authenticated access to PostgreSQL databases for Claude AI, enabling users to browse database tables, discover schemas, and execute custom SQL queries through natural language interaction.
    -
  • A
    license
    A
    quality
    A
    maintenance
    Query and manage PostgreSQL databases from Claude Code, Cursor, and any MCP client, with read-only by default and built-in schema introspection, EXPLAIN, and performance diagnostics.
    23
    4,335 npm
    5
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables Claude Code to securely interact with PostgreSQL, MySQL, SQLite, and SQL Server databases, featuring read-only mode, query validation, SSH tunneling, and field redaction for production-safe data access.
    2
    MIT