Skip to main content
Glama
vrindha-k

Multi-Database AI Query Agent

by vrindha-k

Multi-Database AI Query Agent (MCP)

CI Python PostgreSQL MCP Claude License

Ask questions across independent PostgreSQL databases. Claude discovers schemas through a real Model Context Protocol server, writes analytical SQL, and receives bounded results from a read-only execution layer. A Rich CLI shows the executed SQL, result tables, and the AI answer.

Portfolio demonstration using synthetic data. This is not a security-certified database gateway. Live Claude answers require your own API key and incur API charges. See the verification report for what was actually executed, including limitations.

Features

  • Five discoverable MCP tools: list_databases, list_tables, get_schema, run_query, explain_query. The CLI uses MCP stdio JSON-RPC, never direct Python tool calls.

  • Database routing, optional enforced database selection, dynamic columns, keys and indexes.

  • Official Anthropic SDK orchestration with multiple tool calls, error feedback and turn budgets.

  • SQLGlot PostgreSQL AST validation, schema authorization, approved analytics functions, read-only transactions, separate database reader roles, timeouts and result budgets.

  • INNER/LEFT joins, subqueries, aggregates, HAVING, nonrecursive CTEs, window functions and date aggregation, with reference queries executed against PostgreSQL.

  • Two different six-table datasets, Docker Compose, pinned dependencies, pytest and Ruff CI.

  • API-key-free /sql and /explain diagnostics for repeatable local demonstrations.

Related MCP server: postgres-mcp

Architecture

flowchart LR
    User[Question in Rich CLI] --> Agent[Anthropic SDK tool loop]
    Agent <-->|Tool definitions and tool results| Claude[Claude API]
    Agent <-->|MCP stdio JSON-RPC| MCP[FastMCP server]
    MCP --> Metadata[SQLAlchemy metadata discovery]
    MCP --> Policy[SQLGlot PostgreSQL AST policy]
    Policy --> Execution[Read-only transaction and bounded results]
    Metadata --> Commerce[(E-commerce PostgreSQL)]
    Metadata --> HR[(HR PostgreSQL)]
    Execution --> Commerce
    Execution --> HR

The MCP client launches python -m app.server as a child process and initializes a ClientSession. It discovers tool schemas using list_tools, sends them to Claude, executes each returned tool_use through session.call_tool, and supplies matching tool_result blocks in the next message. Database URLs and API keys are not included in tool definitions or results. SQL and result data are sent to Claude. The model is instructed to inspect metadata before querying; this workflow is guidance, while SQL authorization is enforced in code and PostgreSQL.

Quick start: Windows 11 + Docker Desktop

Open PowerShell in this repository. Start Docker Desktop and wait for its engine to be ready.

powershell -ExecutionPolicy Bypass -File .\scripts\configure.ps1
code .env
# Add ANTHROPIC_API_KEY in the editor, then save. Never commit .env.
docker compose up -d --wait ecommerce hr
docker compose build agent
docker compose run --rm agent

configure.ps1 generates four random credentials in the ignored .env. It refuses to overwrite an existing file. The Docker image runs as a nonroot user. The server starts automatically when the CLI connects; a separate server terminal is unnecessary for stdio transport.

At the prompt:

/use ecommerce
Which five products generated the most completed-order revenue?
/use hr
What is active headcount by department as of December 31, 2025?
/help
/exit

Full instructions, including native Python setup, all testing commands, reset, troubleshooting, and publishing steps: Windows testing guide.

Reproducible example

Question: “Which five products generated the most completed-order revenue?”

SELECT p.name, SUM(i.quantity * i.unit_price) AS revenue
FROM public.products p
JOIN public.order_items i ON i.product_id = p.id
JOIN public.orders o ON o.id = i.order_id
WHERE o.status = 'completed'
GROUP BY p.id, p.name
ORDER BY revenue DESC, p.name
LIMIT 5;

Product

Gross revenue (USD)

Product 11

25,080.00

Product 08

16,320.00

Product 10

15,600.00

Product 12

12,960.00

Product 07

11,760.00

This is a verified reference query, not a recorded live Claude generation. A successful AI answer should summarize these values if it uses the same revenue definition. Seed dates are fixed in 2025; “last month” relative to today may correctly return no rows. Use explicit 2025 dates.

Actual MCP terminal capture

14 questions, SQL and database-calculated outputs include segment counts, average order values, regional revenue, inactive customers, salary history, headcount, attendance, RANK/DENSE_RANK, LAG/LEAD and running totals. Decimal values are serialized as strings to preserve precision. Dates are ISO strings. Results are arrays with a separate column list, so duplicate column names do not silently overwrite values.

Data model

Database

Tables

Synthetic volume

ecommerce

customers, products, categories, orders, order_items, payments

60 customers, 12 products, 720 orders, 1,440 items, 648 payments

hr

employees, departments, positions, salaries, attendance, performance_reviews

80 employees, 4 departments, 160 salary records, 2,400 attendance rows, 80 reviews

Orders are either completed or cancelled. Gross revenue is the sum of completed-order item quantity times unit price; it excludes tax, refunds and discounts, which are not modeled. HR termination dates support headcount and departures; a turnover percentage additionally requires an explicitly agreed denominator. Current salary uses the latest effective date.

Configuration

Variable

Purpose / default

ANTHROPIC_API_KEY

Secret, optional for diagnostics/tests; required for natural language

ANTHROPIC_MODEL

Configurable Claude model ID; default claude-sonnet-4-6

DATABASES_JSON

JSON array of {id, description, url, schemas}; default []

DATABASE_CONFIG_FILE

Optional local JSON array file; takes precedence over JSON env value

STATEMENT_TIMEOUT_MS

Per-statement limit, default 3000; allowed 10–30000

MAX_ROWS

Default and maximum requested query rows; default 100, hard maximum 1000

MAX_CELL_CHARS

String/cell truncation; default 4000, maximum 10000

MAX_AGENT_TURNS

Claude round-trip budget; default 12, maximum 30

ECOMMERCE_ADMIN_PASSWORD, HR_ADMIN_PASSWORD

Compose initialization only

ECOMMERCE_READER_PASSWORD, HR_READER_PASSWORD

Separate per-database readers

ADMIN_URL

Native/CI seed script only; never required by the app

Additional databases require only configuration and a separately provisioned read-only role:

[
  {
    "id": "analytics",
    "description": "Authorized synthetic analytics database",
    "url": "postgresql+psycopg://reader:URL_ENCODED_SECRET@localhost:5432/analytics",
    "schemas": ["public", "reporting"]
  }
]

Store this in ignored databases.local.json, set DATABASE_CONFIG_FILE=databases.local.json, and grant SELECT/USAGE only on the intended tables/schemas. Use postgresql+psycopg URLs. Avoid broad grants and reader membership in privileged roles. The demo Compose service sets its own internal-hostname DATABASES_JSON; edit that override when adding containerized databases. localhost:5541/5542 is for host Python, ecommerce:5432 and hr:5432 for the agent container.

Tests and CI

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
.\.venv\Scripts\ruff.exe check .
.\.venv\Scripts\ruff.exe format --check .
.\.venv\Scripts\python.exe -m pytest -q -m "not integration"
# After starting and configuring both seeded databases:
.\.venv\Scripts\python.exe -m pytest -q -m integration

Or use uv sync --frozen --extra dev and uv run ... for exact versions from uv.lock. Tests do not require an Anthropic key. Standard tests mock the paid Claude boundary. Integration tests use real PostgreSQL and real MCP stdio, including the agent loop with mocked Claude replies. They compare all reference queries to stored PostgreSQL outputs and check ACLs even after turning off transaction read-only in a direct test connection.

GitHub Actions runs Ruff, unit tests, seeded PostgreSQL integration tests, and a separate Docker Compose build/integration job. Workflow configuration is not evidence that a hosted run passed.

Security and limitations

  • SQL is parsed as PostgreSQL, normalized and executed from the validated AST. Only one SELECT/read-only WITH is accepted; DDL/DML anywhere in the tree, writable CTEs, locks, SELECT INTO and recursive CTEs are rejected. Functions fail closed against a small allowlist.

  • Physical tables are resolved through SQL scopes, checked against configured schemas and current SELECT privileges, and explicitly schema-qualified. Views, system tables, UDFs, extensions and cross-database SQL joins are deliberately unsupported.

  • Both examples use separate NOSUPERUSER/NOCREATEDB/NOCREATEROLE readers, no schema CREATE or database TEMP privilege, SELECT grants, default read-only, a 3-second role timeout and 32 MB temporary-file cap. Every execution also opens a read-only transaction. Privileged roles are rejected at connection time. Additional databases must preserve equivalent least privilege.

  • Pool size 2 per database, no overflow, connection and lock timeouts, 4 MB work_mem, no parallel workers, row caps, 128-column cap, string truncation and 256 KB row payload budget bound work and responses. These are per-query controls, not global admission control or an OS memory cap.

  • EXPLAIN runs without ANALYZE. Planning itself is still subject to role/transaction controls. Indexes support customer/date, product and department access. Small demo tables may correctly use sequential scans. No claim is made that every generated query is optimal.

  • API keys and URLs are secret configuration; errors and application logs omit raw driver exceptions, SQL literals and DSNs. Database/table descriptions and results are untrusted LLM input. Prompt injection may change the model's answer, but cannot bypass SQL/DB policy.

  • Schema names, comments, SQL and query results leave your machine when using Claude. Use only data you are authorized to disclose. This demo contains no real people or customer data.

  • stdio is local and has no network listener. Do not expose this as a remote service without authentication, authorization, rate limits, audit controls and independent security review.

Repository map

app/           configuration, metadata/execution, SQL policy, MCP server, agent, CLI
db/            deterministic schemas/data and least-privilege Docker initialization
tests/         parser, configuration, orchestration, real MCP and PostgreSQL tests
examples/      reference questions and verified outputs
scripts/       secure demo configuration, native/CI seeding, example verification, capture
docs/          Windows testing, interview walkthrough, examples, verification evidence
.github/       unit/integration and Compose CI workflow

Interview walkthrough and next steps

Read the component walkthrough for the request lifecycle, schema discovery, authorization, testing strategy, tradeoffs and interview talking points.

Future work: query cost/admission budgets, richer type-safe result models, per-user/table authorization, structured audit records with redaction, independently reviewed AST policies, prompt-injection evaluations, larger randomized datasets, and SDK v2 migration. The official MCP SDK v1 FastMCP API is deliberately pinned to its compatible major version in this implementation.

MIT licensed. No hosting deployment is needed; run locally and showcase the source on GitHub.

Available Tools

5 tools
explain_queryB

Describe SQL structure and PostgreSQL EXPLAIN estimates, without ANALYZE.

NameRequiredDescriptionDefault
sqlYes
database_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior3/5

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

With no annotations, the description carries the full disclosure burden, and 'without ANALYZE' does add real behavioral value: the query is planned, not executed. However, it says nothing about permissions required, side-effect safety, or how invalid SQL is handled.

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 tight sentence with no filler, and the operative constraint ('without ANALYZE') is placed where it will be read. Nothing here is redundant.

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?

An output schema exists, so return-value explanation is not required, and the ANALYZE clause covers the key semantic distinction. Still, with zero annotations the description should say more about execution safety and prerequisites for a plan-inspection tool.

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 for both parameters, and it adds no meaning for 'sql' or 'database_id'. The names are largely self-explanatory, which prevents a 1, but the description contributes nothing beyond them.

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 gives a specific verb ('Describe') with two clear resources: SQL structure and PostgreSQL EXPLAIN estimates. The clause 'without ANALYZE' distinguishes it from a query-execution tool like run_query, though it never names that sibling explicitly.

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?

Usage is only implied: an agent can infer this is for inspecting a query plan without executing it. There is no explicit 'use this when...' or exclusion naming run_query as the alternative when actual execution is wanted.

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

get_schemaB

Inspect columns, keys, foreign-key relationships and indexes of discovered tables.

NameRequiredDescriptionDefault
database_idYes
table_namesYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full behavioral burden. 'Inspect' strongly implies a read-only operation and the description discloses what schema details are examined, but it does not explicitly confirm read-only safety, permissions, or side effects.

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 efficiently communicates the tool's scope and inspected objects.

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?

An output schema exists, so return values need not be explained in the description. However, with no annotations and 0% parameter description coverage, the definition leaves gaps around parameter meaning and usage context that the description could have filled.

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 for undocumented parameters. It implies table names via 'discovered tables' but never explains database_id or table_names, leaving both required parameters semantically underspecified.

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 uses a specific verb, 'Inspect', and names the exact schema elements returned: columns, keys, foreign-key relationships, and indexes. It is clearly distinct from list_tables in substance, but it does not explicitly name or contrast with sibling tools.

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 phrase 'discovered tables' implies this tool is used after tables have been listed, giving some contextual usage guidance. However, it does not state when to use this versus list_tables, run_query, or explain_query, nor does it mention prerequisites or exclusions.

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

list_databasesA

List configured database identifiers, descriptions and availability; no credentials.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior3/5

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

With no annotations, the description carries the full burden; it does disclose a meaningful trait — that no credentials are returned — plus the 'availability' dimension, which hints results may be filtered by availability. It says nothing about permissions required, ordering, pagination, or whether unavailable databases are omitted vs flagged.

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 tight sentence with the resource front-loaded and the security-relevant caveat ('no credentials') appended. No filler and nothing redundant.

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?

A simple, parameterless read tool with an output schema that covers the return shape; the description adds the useful 'availability' and 'no credentials' framing. What remains missing — result ordering and handling of unavailable databases — is minor given the output schema exists.

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?

Zero parameters, so baseline 4 applies. There is nothing parameter-wise for the description to compensate for, and the schema is trivially complete.

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?

States a specific verb+resource ('List configured database identifiers') and enumerates the returned fields (identifiers, descriptions, availability). It implicitly separates itself from sibling list_tables by naming database-level rather than table-level resources, though it never names the alternative outright.

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?

Usage is only implied: an agent can infer this is the discovery entry point before list_tables/get_schema, but the description never says when to prefer it or what it excludes. No explicit when/when-not guidance or named alternatives.

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

list_tablesC

Discover authorized base tables, comments and approximate row counts.

NameRequiredDescriptionDefault
database_idYes
schema_nameNo

Output Schema

NameRequiredDescription

No output parameters

TDQS

C2.9/5.0
Behavior3/5

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

With no annotations, the description carries the full behavioral burden. It does disclose that results are limited to authorized tables and that row counts are approximate, which is useful, but it omits read-only confirmation, permission requirements, and any pagination or result-size behavior.

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 definition is a single front-loaded sentence with no wasted words. It is appropriately concise, though that concision comes at the cost of missing usage and parameter context.

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?

An output schema exists, so return values need not be explained. However, with no annotations and 0% parameter description coverage, the description should do more to explain how to invoke the tool and when to choose it over siblings; it currently covers only the surface purpose.

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% for two parameters, and the description does not mention database_id or schema_name at all. The parameter names are somewhat self-explanatory, but the description adds no meaning about required database selection or optional schema filtering.

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 and resource: discover authorized base tables, with comments and approximate row counts. It is clear enough to distinguish from list_databases and get_schema, though it does not explicitly name those siblings.

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?

It implies the tool is for discovering tables, but gives no explicit when-to-use guidance, no exclusions, and no comparison to alternatives like get_schema or run_query. An agent must infer routing from the name alone.

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

run_queryB

Execute one validated read-only SELECT/CTE, returning bounded structured results.

NameRequiredDescriptionDefault
sqlYes
max_rowsNo
database_idYes

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior3/5

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

With no annotations, the description carries full behavioral burden and does disclose key traits: read-only, single-statement, validated, and bounded results. It says nothing about timeouts, row-cap enforcement, permission requirements, or what happens on validation failure, which are material for arbitrary SQL execution.

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 front-loaded sentence with no filler; the operative constraints (one statement, read-only, bounded) come before the result clause. Every word earns its place.

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?

An output schema exists, so return values need no explanation, and the core constraint set is present. For an arbitrary-SQL execution tool with zero annotation coverage and undocumented parameters, though, missing error/timeout behavior and database_id sourcing leave it only minimally complete.

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 explain all three parameters and does not. 'Bounded' loosely gestures at max_rows and 'one SELECT/CTE' at sql, but database_id (the required identifier) is never mentioned nor its provenance (list_databases) indicated.

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?

States a specific verb (Execute) and resource (one validated read-only SELECT/CTE) with a clear output shape ('bounded structured results'). This implicitly separates it from explain_query and the list_/get_schema siblings, but no sibling is named explicitly.

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?

'one validated read-only SELECT/CTE' implies the boundary (single statement, read-only, validation applies), which is real guidance. However, it never states when to prefer explain_query for plans, or what to do when a query is rejected, leaving usage context to inference.

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. 5 tool updatesv0.1.0
    • First observedexplain_query
    • First observedget_schema
    • First observedlist_databases
    • First observedlist_tables
    • First observedrun_query

TDQS

A3.6/5.0

Scored across 5 tools

Disambiguation5/5

Each tool maps to a distinct stage of a read-only analytics workflow: database discovery, table discovery, schema introspection, execution, and plan explanation. The only superficially similar pair (run_query vs explain_query) is clearly separated by 'returns bounded structured results' versus 'EXPLAIN estimates, without ANALYZE'. An agent can pick the right tool without guessing.

Naming Consistency5/5

All names are snake_case verb_noun pairs (list_*, get_*, run_*, explain_*) with a consistent, predictable structure. The verbs accurately signal the operation type, and there are no camelCase or style outliers.

Tool Count5/5

Five tools is tightly scoped for a read-only query agent and every tool earns its place in the discovery→introspection→execution chain. Nothing appears redundant or bolted on.

Completeness4/5

The core lifecycle for a read-only agent (discover → inspect → execute → explain) is fully covered, and the absence of write tools is clearly intentional. Minor gaps remain: no cross-database/column search or namespace listing, so an agent must walk databases/tables sequentially to locate a field.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude to query a Postgres analytics schema via a read-only MCP server, with tools auto-generated from live database introspection and configurable SQL queries defined in YAML.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables read-only, SELECT-only querying of any Postgres database through MCP-compatible clients like Claude, with schema introspection and guarded SQL execution.
    MIT
  • F
    license
    A
    quality
    C
    maintenance
    Enables read-only access to a PostgreSQL database, allowing users to inspect schema, generate SQL from natural language, and execute read-only queries via MCP.
    5
    -