mcp-server
Provides tools for inspecting a PostgreSQL database schema and executing read-only SQL queries, with optional natural-language to SQL generation.
Click on "Install 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., "@mcp-servershow me the first 10 orders"
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.
FastMCP PostgreSQL server
A small learning project that exposes an existing PostgreSQL database through an MCP server. It is intentionally narrow: inspect the schema, turn a natural-language request into SQL, and execute read-only queries.
The generate_query tool sends the prompt and database schema to a configured
LLM through an OpenAI-compatible API, then validates the returned SQL before
passing it back to the MCP client.
How the project is organized
src/mcp_server/
server.py FastMCP application and tool definitions
database.py PostgreSQL connection, schema discovery, read-only queries
sql_generator.py LLM-backed prompt-to-SQL generation and validation
tests/ Unit tests for SQL generation and database helpersThe server exposes five tools:
Tool | Purpose |
| List tables visible to the configured database role |
| Return columns and PostgreSQL data types |
| Ask the configured LLM for a validated read-only query |
| Execute one |
| Generate and execute a query immediately (dangerous) |
database.py sets PostgreSQL's default_transaction_read_only for every
connection. Still use a database role with only the permissions this server
needs; application-level checks are defense in depth, not authorization.
Related MCP server: MCP PostgreSQL Server
Setup
Requires Python 3.11+ and network access to PostgreSQL.
py -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
Copy-Item .env.example .envEdit .env with the connection string for your existing database:
DATABASE_URL=postgresql://user:password@localhost:5432/database_name
DB_CONNECT_TIMEOUT=5The server and the VS Code launch profiles load .env automatically. Do not
put the connection string in a PowerShell profile or hard-code it in
.vscode/launch.json. Never commit .env; it is ignored by Git, while
.env.example is safe to commit.
Use the exact connection values from pgAdmin's connection properties:
Host name/address, Port, Maintenance database (usually the database
name), Username, and password. For example, a local database commonly uses
localhost, port 5432, and postgres, but do not assume those values.
Before using the Inspector, test the same connection directly:
python -c "from mcp_server.database import Database; print(Database().list_tables())"If that command times out, compare .env with pgAdmin and check that the host,
port, database, username, and SSL settings match. DB_CONNECT_TIMEOUT limits
how long a connection attempt waits; it does not make an unavailable database
available.
Run and test
Run the unit tests:
py -m pytestConfirm the FastMCP application imports and registers its tools:
python -c "from mcp_server.server import mcp; print([tool.name for tool in mcp._tool_manager.list_tools()])"Start the server over stdio:
mcp-sql-serverVS Code launch profiles
The project includes three profiles in .vscode/launch.json. Open the
Run and Debug view (Ctrl+Shift+D), select a profile, and press F5:
Launch MCP server starts
mcp_server.serverwith.envloaded. The server uses stdio and waits for an MCP client, so an idle terminal is expected.Launch MCP Inspector runs the MCP CLI's
devcommand for this server and opens the browser-based Inspector. It uses.envthroughscripts/launch_inspector.py; no PowerShell environment variable is needed.Run tests launches
pytest -qwith the same project environment. Set a breakpoint in a test or application file to debug it.
Select the Python interpreter from .venv when VS Code prompts for one. The
Python extension and its debugger (debugpy) must be installed. The launch
profiles load .env; environment variables configured by VS Code or the
terminal can still take precedence according to VS Code's environment rules.
The process waits for an MCP client. It is not an HTTP server and will appear
idle in the terminal; that is expected. Configure an MCP client or the MCP
Inspector to launch mcp-sql-server from this project environment. Then try:
list_tablesdescribe_tablewith a table name such asusersorreporting.ordersgenerate_querywith a request such as “show the first 10 orders”Review the generated SQL, then call
run_readonly_query
execute_generated_query combines steps 3 and 4. It is intentionally marked
DANGEROUS in the tool description and response because it executes
model-generated SQL without giving you a separate review step. Prefer
generate_query, inspect the SQL, and then call run_readonly_query.
Read-only mode prevents data modification, but it does not prevent expensive
queries, excessive result sets, sensitive data exposure, or incorrect results.
Using an LLM for SQL generation
generate_query calls an OpenAI-compatible chat-completions endpoint. The
server sends the user's prompt plus the PostgreSQL schema, then validates the
response before returning it. The default configuration targets local Ollama:
Ollama
Ollama is a separate application that runs open-source LLMs locally and exposes them through a local API. It is not installed inside this Python project or virtual environment.
Download and install Ollama from the official page:
Verify the installation, download a model, and start the local service:
ollama --version
ollama pull qwen2.5-coder:3b
ollama serveOllama normally listens on http://localhost:11434. The MCP server connects to
that endpoint using the following settings.
Set these values in .env:
LLM_BASE_URL=http://localhost:11434/v1
LLM_MODEL=qwen2.5-coder:3b
LLM_API_KEY=
LLM_TIMEOUT=60If generate_query cannot reach Ollama, verify the service and model before
restarting the MCP Inspector:
ollama list
Invoke-RestMethod http://localhost:11434/api/tagsLLM_MODEL must exactly match a name shown by ollama list, for example
qwen2.5-coder:3b. If Ollama is running on another host or port, update
LLM_BASE_URL accordingly. Ollama's OpenAI-compatible URL includes /v1.
For vLLM, LM Studio, or a hosted OpenAI-compatible service, change
LLM_BASE_URL, LLM_MODEL, and LLM_API_KEY as appropriate. Restart the MCP
server after changing .env.
Keep generation separate from execution. Model output is untrusted text:
the generator accepts only one SELECT or WITH statement, and the database
layer independently enforces read-only transactions. For production, add SQL
parsing, query timeouts, result-size limits, query logging, and schema/table
allow-lists.
Open-source model options
These are good starting points for text-to-SQL experimentation. Run them locally with Ollama, vLLM, or another OpenAI-compatible server, then call that endpoint from Python.
Qwen2.5-Coder 3B/7B/14B — strong code and SQL generation for its size; a practical local starting point.
DeepSeek-Coder V2 Lite — capable coding model with useful SQL reasoning; check its memory requirements before choosing a larger variant.
SQLCoder — specifically tuned for text-to-SQL; useful when SQL generation is the primary task rather than general conversation.
Qwen3-Coder — newer coding-focused option; consider it when you have more GPU memory or a hosted inference endpoint.
Llama 3.1/3.2 Instruct — broad ecosystem and easy local deployment; may need stronger schema/prompt constraints for reliable SQL.
Hardware recommendations for less than 8 GB of VRAM
For a GPU with less than 8 GB of VRAM, start with a 3B–7B model in a 4-bit quantized format. The model, context window, and runtime overhead all consume VRAM, so avoid assuming that a model's parameter count is its total memory requirement.
Best starting point: Qwen2.5-Coder 3B or 7B at 4-bit quantization.
SQL-focused option: SQLCoder in its smallest available quantized variant, if the model fits comfortably with your schema context.
Good fallback: a 3B instruct/coder model with a concise schema prompt.
Avoid initially: 14B+ models, large context windows, and unquantized weights.
With Ollama, try a 3B model first and keep the schema context focused on tables relevant to the request. If a 7B model is slow, runs out of memory, or causes the system to swap, move down to 3B or use a hosted endpoint. CPU inference works for experimentation but will usually have noticeably higher latency.
Model quality depends heavily on schema context and evaluation. Start with a small model and a fixed set of representative prompts, compare generated SQL against expected queries, and only then consider fine-tuning or a larger model. Check each model's license and hardware requirements before shipping it.
Useful next steps
Add a
get_schematool that returns only the tables relevant to a request.Add SQL parsing/validation and a configurable maximum row count.
Add integration tests against a disposable PostgreSQL instance.
Add query timing and audit logging without logging credentials or sensitive result data.
Available Tools
5 toolsdescribe_tableB
Return column metadata for a table.
| Name | Required | Description | Default |
|---|---|---|---|
| table_name | Yes |
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 transparency burden. 'Return column metadata' implies a safe, read-only operation, but no explicit statement about side effects, permissions, or behavior on missing tables is provided.
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 sentence, no filler, front-loaded with the action verb. It is as concise as possible while communicating the core function.
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?
With an output schema present and only one parameter, the tool is inherently simple. The description is nearly sufficient, but lacks usage context relative to sibling tools and any note about table name qualification, leaving a small gap.
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?
The single required parameter table_name has no schema description (0% coverage). The description only says 'a table' and does not add detail about expected format, qualification, or allowed values, so the agent gets little beyond the parameter name.
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 identifies a specific action ('Return') and object ('column metadata for a table'), making the tool's purpose immediately clear. It does not explicitly call out sibling tools, so it stops short of the top score.
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 provides no guidance on when to use describe_table rather than siblings like list_tables or generate_query. There is no mention of use cases, prerequisites, or exclusion conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
execute_generated_queryA
DANGEROUS: generate SQL from a prompt and execute it immediately.
This executes model-generated SQL without a separate review step. Use generate_query and run_readonly_query instead when possible.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It warns 'DANGEROUS' and explains that model-generated SQL is executed immediately without review, which conveys the primary risk profile. It could be more explicit about potential write/destructive effects, but the warning is substantial.
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 sentences with no filler. It front-loads the most critical information ('DANGEROUS') and each sentence adds essential context about behavior and alternatives.
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 tool with an output schema, the description covers the core behavior, risk, and alternatives. It is slightly lacking in explicit details about prompt semantics and side effects, but overall the agent has enough to call it correctly and safely.
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 0%, so the description must explain the 'prompt' parameter. It says 'generate SQL from a prompt,' which clarifies that the prompt is the natural-language input for SQL generation, but it does not specify prompt expectations, format, or constraints. This is minimal compensation for a complete lack of schema descriptions.
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 precise action: generate SQL from a prompt and execute it immediately. It clearly distinguishes itself from siblings by noting that it executes without a separate review step, unlike generate_query and run_readonly_query.
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 explicitly steers agents toward safer alternatives: 'Use generate_query and run_readonly_query instead when possible.' This gives a clear preference order, though it does not define exact conditions for when this tool must be used.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_queryA
Turn a natural-language request into one read-only SQL statement.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes |
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 burden of behavioral disclosure. It discloses that the tool produces one read-only SQL statement and does not claim to execute it, which are useful behavioral traits. However, it does not elaborate on potential constraints, validation behavior, or how it relates to execution beyond that implication.
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 a single, front-loaded sentence with no wasted words. Every phrase adds value: 'natural-language request' defines the input, 'read-only' signals safety, and 'SQL statement' defines the output.
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 generation tool with an output schema, the description is nearly complete: it defines the input, the output, and the read-only nature. It would be more complete with an explicit note about not executing the generated SQL and when to choose this over the sibling execution tools.
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?
The schema has zero description coverage, so the description must clarify the parameter. It does this by identifying the input as a 'natural-language request,' which adds meaning to the bare 'prompt' property. It also defines what the output will be, helping the agent understand the transformation.
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 action ('turn ... into') and resource/outcome: a natural-language request becomes one read-only SQL statement. It clearly distinguishes generation from the sibling execution tools by describing the output as a statement rather than a run operation, though it does not explicitly name an alternative.
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 implies the tool is used when a natural-language request needs to be converted into SQL, and the read-only qualifier signals a safe generation context. It does not explicitly say when to use this tool instead of run_readonly_query, execute_generated_query, or the table-introspection siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tablesA
List the tables available in the configured read-only database.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must carry the behavioral disclosure burden. It does note the database is 'read-only', implying this is a safe read operation, but it does not disclose potential edge behaviors like whether views or system tables are included, whether sorting is applied, or any error conditions. The read-only hint provides some context but not comprehensive behavioral detail.
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 a single, tightly worded sentence with no redundant phrases. Every word contributes meaning: 'List' gives the action, 'tables' gives the object, and 'configured read-only database' gives the scope.
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 zero-parameter listing tool with a provided output schema, the description is nearly complete. It tells the agent what the tool does, and the output schema can document the return structure. It lacks only a brief note about when to use it in the broader tool workflow, but that is already captured by the low usage_guidelines score.
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?
The input schema has zero parameters, so parameter documentation is not needed. With 0 parameters, the baseline is 4, and the description correctly omits parameter explanations because none exist.
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 ('List') and a specific resource ('tables available in the configured read-only database'). It clearly distinguishes itself from sibling query and description tools because it enumerates all tables rather than running a query or describing one table.
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 no explicit guidance on when to use this tool versus alternatives such as describe_table or run_readonly_query. The context signals list sibling tools, but the description does not reference them or define conditions for choosing this tool over them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_readonly_queryA
Execute a single read-only SELECT or WITH query and return its rows.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
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 discloses key behavior: the operation is read-only and returns query rows. It doesn't cover permissions, dialects, limits, or error behavior, but the core safety-relevant trait is explicit.
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 sentence with no filler; the operative verb and key constraints ('read-only', 'single', 'SELECT or WITH') come first and the result is stated.
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 tool with an output schema, the description captures the input constraint and the output shape. It doesn't need to restate the schema's return format. The main gap is no explicit sibling-selection guidance, but that is already accounted for under usage guidelines.
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?
The schema's query parameter has no description, so the description must compensate. It adds meaning by restricting the string to a single read-only SELECT or WITH query, but it gives no syntax hints, examples, or statement-termination expectations.
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 an explicit action ('Execute') and a constrained resource ('single read-only SELECT or WITH query'), plus the result ('return its rows'). It doesn't name sibling tools, but the read-only SELECT/WITH restriction helps an agent distinguish it from execute_generated_query.
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 implies usage for read-only query execution, but never states when to prefer this over execute_generated_query, generate_query, or not to use it. There are no explicit alternatives or exclusion conditions.
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. Dates show when Glama detected each change.
5 tool updates
v0.1.0- First observed
describe_table - First observed
execute_generated_query - First observed
generate_query - First observed
list_tables - First observed
run_readonly_query
TDQS
Most tools are clearly distinct: schema inspection (list_tables, describe_table), SQL generation (generate_query), and query execution (run_readonly_query). execute_generated_query overlaps by combining generation and execution, but its DANGEROUS warning and guidance to prefer the separate steps mitigate confusion.
All tool names follow a consistent snake_case verb_noun pattern, with optional qualifiers like readonly and generated. The naming clearly indicates the action and target (list_tables, describe_table, generate_query, run_readonly_query, execute_generated_query).
Five tools is well-scoped for a read-only database interface: schema exploration, query generation, exact query execution, and a dangerous combined shortcut. Each tool contributes a distinct capability without unnecessary bloat.
The tool surface covers the complete read-only workflow: see what tables exist, inspect schema, translate natural language to SQL, and execute read-only queries. The optional generate-and-execute tool also fills the convenience path without introducing an obvious dead end.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
- dataOAuthco.thinair
Read-only PostgreSQL, MySQL, SQL Server access via MCP — 24 dialect-aware hosted tools.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with PostgreSQL databases through MCP, allowing users to explore database structures, inspect table schemas, and execute read-only SQL queries.-
- AlicenseNot gradedqualityCmaintenanceEnables secure read-only access to PostgreSQL databases, allowing users to list tables, query schemas, execute SELECT statements, and inspect table structures through natural language interactions.6074MIT
- FlicenseNot gradedqualityCmaintenanceProvides read-only access to PostgreSQL databases, enabling querying, schema exploration, and table metadata retrieval via MCP tools like query, list-tables, describe-table, list-schemas, and list-environments.-
- AlicenseNot gradedqualityCmaintenanceEnables inspecting database schemas and executing read-only SQL queries on a PostgreSQL database via MCP tools.7MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/eastonjeff/mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server