mcp-dbserver
Provides read-only access to MongoDB Atlas collections, including listing collections, retrieving documents, scanning documents, counting documents, and running vector search against Atlas Vector Search.
Provides read-only access to PostgreSQL databases via a fixed set of allowlisted queries, including listing available queries, executing them, and running pgvector-powered semantic search over the demo document dataset.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-dbserversemantic search the demo data for content similar to 'database security'"
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.
mcp-dbserver
A self-built MCP server that gives an AI agent — Claude Code, Claude Desktop, or any MCP-compatible client — read-only, security-scoped access to three database engines at once: PostgreSQL (with pgvector), DynamoDB, and MongoDB Atlas (with Atlas Vector Search). It's a personal project extending 17+ years of multi-cloud database architecture work into the AI/agentic tooling space: the goal isn't "an agent can query a database," it's demonstrating the same least-privilege, defense-in-depth discipline a production reference architecture would demand, applied to a caller that's an LLM instead of a service.
No employer data, schemas, or business logic (current or former) appears anywhere in this repo — only public or synthetic data, generated specifically for this project.
Architecture
flowchart LR
Client["MCP client<br/>(Claude Code / Claude Desktop)"]
subgraph Server["mcp-dbserver (stdio)"]
direction TB
Tools["Fixed tool surface<br/>(no generic 'run query' tool)"]
Guard["guardrails.py + allowlist.py<br/>read-only + row-limit re-check"]
Tools --> Guard
end
Client -- "MCP tool calls" --> Tools
Guard --> PG[("PostgreSQL + pgvector<br/>RDS, IAM or password auth")]
Guard --> DDB[("DynamoDB<br/>fixed table-target registry")]
Guard --> Mongo[("MongoDB Atlas + Vector Search<br/>fixed collection-target registry")]Every arrow into a database is a named, allowlisted operation — never raw SQL, a raw MongoDB filter, or a raw DynamoDB key condition. See ARCHITECTURE.md for the full design.
Related MCP server: Company Data MCP Server
Security model
This is the part of the project meant to differentiate it from a typical "point an agent at a database" demo. Full detail (including two things found by actually testing the guardrails, not just designing them) lives in ARCHITECTURE.md — summary:
Read-only, full stop. No write, update, or delete tool exists for any engine in v1. A write-capable version, if it ever exists, is a separate project with its own threat model.
A documented boundary, found by testing it. The "no write tool" guardrail constrains what an agent can do through the MCP protocol. It cannot constrain a code-capable client (like Claude Code, as opposed to a chat-only client like Claude Desktop) that has independent access to the same credentials. In testing, Claude Code correctly found no delete tool — then wrote its own
psycopgscript and attempted the delete directly, bypassing the MCP server entirely. It failed only because the configured database role lacked write privilege. That makes the database-/IAM-level read-only role the real last line of defense against a code-capable client, not the absence of a write method in this code — documented explicitly rather than left implicit.No raw queries from the agent. Every operation is a named, allowlisted shape with typed parameters — a fixed SQL template (Postgres), a fixed table/collection target registry plus a typed key (DynamoDB/MongoDB) — never a filter document, key-condition expression, or SQL string built from agent input. An earlier draft of the vector search tool took a table/column name as a direct argument and was caught and fixed (a real SQL injection surface via f-string interpolation) before the server was ever wired up to a live client.
Defense in depth at execution time. Even an allowlisted Postgres query is re-validated by
guardrails.pybefore running (rejects anything that isn'tSELECT/WITH, rejects stacked statements, enforces a row-limit ceiling regardless of what's requested), and every connection setsdefault_transaction_read_only = onat the database level.Credentials: environment variables only, never logged, never hardcoded. RDS IAM database authentication is supported and preferred over a stored Postgres password (a fresh ~15-minute token per connection via
rds:GenerateDBAuthToken, no long-lived DB secret at all).
Supported engines & tools
Engine | Tools |
PostgreSQL + pgvector |
|
DynamoDB |
|
MongoDB Atlas + Vector Search |
|
Full per-tool descriptions and the reasoning behind each one are in
ARCHITECTURE.md. semantic_search_documents
and semantic_search_mongodb run against the same demo dataset and the
same local embedding model, specifically so pgvector and Atlas Vector
Search results can be compared directly.
Setup
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # fill in your own, personal, non-work credentialsRun the test suite (no live database required — guardrail/allowlist logic is unit tested against fakes for all three engines):
pytestRun the MCP server (stdio transport, for local use with Claude Code / Claude Desktop):
mcp-dbserverTools are only registered for engines whose required environment
variables are set — e.g. with only POSTGRES_DSN set, only the Postgres
tools appear. See .env.example for every variable, per engine.
Postgres demo dataset
data/demo_documents.jsonl is a small, synthetic set of ~30 short
software/infra explainer snippets (written for this project). Load it
and generate embeddings locally (fastembed's ONNX runtime — offline, no
external API key, no torch/torchvision dependency):
python scripts/load_demo_dataset.py
python scripts/smoke_test_postgres.py # connectivity + read-only guardrail
python scripts/verify_demo_dataset.py # row count + semantic search sanity checkDynamoDB
Tables aren't configured via environment variables — accessible tables
come from a fixed registry in engines/dynamodb.py (_TABLE_TARGETS).
Set AWS_REGION (and standard AWS credentials via env vars/profile/
instance role, scoped to dynamodb:GetItem/Scan/DescribeTable on the
registered table ARN(s)) to enable the *_dynamodb_* tools.
MongoDB Atlas demo dataset
Mirrors the Postgres setup exactly — same dataset, same embedding model —
so results are directly comparable. Set MONGODB_URI/MONGODB_DATABASE
(Atlas user with the built-in read role, not readWrite), then:
python scripts/load_demo_dataset_mongodb.py # upserts data + creates the Atlas Vector Search index
python scripts/verify_demo_dataset_mongodb.py # index builds asynchronously; re-run if search comes back emptyProject layout
src/mcp_dbserver/
guardrails.py # read-only + row-limit enforcement, engine-agnostic
allowlist.py # named, parameterized Postgres query registry
config.py # env-var credential loading, per engine
engines/
postgres.py # allowlisted queries + pgvector semantic search
dynamodb.py # fixed table-target registry, get/scan/count
mongodb.py # fixed collection-target registry, get/list/count/$vectorSearch
server.py # MCP entrypoint, registers tools per configured engine
tests/ # guardrail/allowlist/engine unit tests, all three engines (no live DB needed)
scripts/ # demo dataset loaders/verifiers, Postgres smoke testWhat I'd do differently at production scale
Being explicit about what v1 deliberately doesn't solve signals more than pretending it's production-complete:
Client ↔ server authentication. v1 runs over stdio, launched directly by the client as a subprocess — the OS process boundary is the trust boundary, which is fine for local, single-user use and not fine for anything else. A networked deployment (HTTP/SSE, reachable by more than one client) needs per-client API keys scoped per-engine, and TLS termination in front of the server, before it's anything but a demo.
Observability. No query logging or metrics yet. At minimum, before any networked deployment: which named query/operation was called, when, and whether it succeeded — deliberately never parameter values or row contents, to avoid quietly building a second copy of the data in logs.
Rate limiting. Not implemented; only matters once the server is reachable by more than a single local stdio client, but it's a gap worth naming rather than discovering under load.
MySQL. Explicitly out of scope for v1. Would follow the same allowlist + guardrail pattern as Postgres if added — no new design needed, just the fourth engine's worth of plumbing.
The DynamoDB/MongoDB filter-shape question got simpler than planned, not more complex. The original design considered a typed schema per allowlisted filter for DynamoDB/MongoDB. What shipped instead is smaller: a fixed target registry plus a fixed, small set of named operations per engine, with no generic
find(filter)orquery(key_condition)tool at all. Worth calling out because the instinct to build a validation DSL was the more "impressive-sounding" option, and the simpler one turned out to close the same gap more reliably — there's no permissive shape for$whereor an arbitrary key condition to hide in, because there's no field for one.
Maintenance
Related MCP Connectors
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Let AI agents query data and act across all your business apps via MCP.
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceProvides read-only access to PostgreSQL databases via MCP, enforcing least-privilege roles, row-level security, masked views, and SQL AST guardrails to prevent data leakage and unauthorized operations, enabling AI agents to safely query sensitive production data.MIT
- FlicenseNot gradedqualityCmaintenanceEnables read-only access to company data across PostgreSQL, MongoDB Atlas, and flat files through MCP tools, allowing AI assistants to query and retrieve information via natural language.-

MCP DB Gatewayofficial
AlicenseNot gradedqualityBmaintenanceProvides governed, read-only PostgreSQL access for AI agents via MCP. Enforces schema/table allowlists, query limits, and audit events.MIT- AlicenseNot gradedqualityCmaintenanceEnables AI agents to safely read SQL Server databases via MCP with structured queries, default-deny table permissions, OAuth authentication, and full audit logging.MIT