Universal Database MCP
A small MCP server that lets an LLM query PostgreSQL, MySQL, MariaDB, SQL Server, or SQLite databases safely — read-only, role-restricted, and with sensitive data blacked out.
README
Anvaya Labs — Universal Database MCP (Simple Version)
A small MCP server that lets an LLM query PostgreSQL, MySQL, MariaDB, SQL Server, or SQLite databases safely — read-only, role-restricted, and with sensitive data blacked out.
Files (4 files, ~650 lines total, no classes/decorators/async)
config.py— plain dictionaries: who can see what, which columns get masked. Edit this file to change any rule.security.py— 4 plain functions: check it's read-only, check the role is allowed, add tenant filtering, mask sensitive values.db_engine.py— 3 plain functions: get schema, run query, explain query. Talks to the actual database.server.py— the 4 tools the LLM can call, each just a try/except around the functions above, with a log line either way.
Keeping database passwords out of chat
db_uri no longer has to be a raw connection string typed into the
conversation. Instead:
- Copy
.env.exampleto.envand fill in real connection strings there. - In chat, refer to a database by its short name — e.g. "query the
proddatabase" — and passdb_uri="prod". The server looks upANVAYA_DB_PRODin the environment and uses that. - Leaving
db_uriempty ("") usesANVAYA_DEFAULT_DB_URIinstead.
A full connection string (containing ://) still works directly if you
pass one — useful for quick local testing — but the recommended pattern
is to never type a real password into the chat at all.
Authentication (for remote/multi-team deployments)
Since other people connect to this server, role can no longer be
trusted as something the LLM just tells the server — anyone could type
role="admin". Instead:
- Generate a secret once and put it in
.env:python -c "import secrets; print(secrets.token_hex(32))"ANVAYA_JWT_SECRET=<paste it here> ANVAYA_MCP_TRANSPORT=http - Whenever someone needs access, mint them a signed token:
uv run python issue_token.py --name alice --role analyst --tenant acme - Give that token to them. Their MCP client connects with it as a
Bearer token. The server verifies the signature on every call and
uses the role/tenant from the token — any
role/tenant_idthey try to pass as arguments is ignored.
If ANVAYA_JWT_SECRET isn't set, the server runs with no auth at all
(fine for local stdio testing on your own machine, not for anything
reachable by other people).
Transport: this uses Streamable HTTP (transport="http"), the current
MCP standard for remote servers — SSE is deprecated as of the 2025-11-25
MCP spec revision.
Deploying for free (Render) so claude.ai (web) can reach it
claude.ai connects to remote MCP servers from Anthropic's cloud, not
from your browser — so this needs a real public HTTPS URL. Local
network / VPN-only hosting won't work for the web client (Claude
Desktop's local stdio config is different and stays working as-is).
Render gives you that for free, with auto-deploy
on every git push.
1. Push this project to a GitHub repo
git init
git add .
git commit -m "Anvaya Universal Database MCP"
git remote add origin https://github.com/YOUR_USERNAME/anvaya-labs-mcp.git
git push -u origin main
2. Create the Render service
- Go to render.com → sign up (no credit card needed for the free tier) → New → Web Service
- Connect your GitHub repo
- Settings:
- Runtime: Python 3
- Build Command:
pip install -r requirements.txt - Start Command:
python server.py - Instance Type: Free
3. Add environment variables (Render dashboard → Environment)
ANVAYA_JWT_SECRET=<your generated secret>
ANVAYA_MCP_TRANSPORT=http
ANVAYA_DEFAULT_DB_URI=sqlite:///test.db
(test.db is committed in this repo as a small demo database — Render's
free tier has no persistent disk, so a database that's part of the
codebase is what survives redeploys. For real data, point
ANVAYA_DEFAULT_DB_URI at an externally hosted database instead —
e.g. a free Postgres from Neon — rather than SQLite.)
4. Deploy
Render builds and deploys automatically. You'll get a URL like
https://anvaya-labs-mcp.onrender.com. Every future git push to
this repo redeploys automatically — no extra steps needed.
Two honest limitations of the free tier:
- The service sleeps after 15 minutes of no traffic, and the first request after that takes 30-50 seconds to wake up — the very first tool call after idling may feel slow or briefly time out.
- No persistent disk, as noted above — anything written to disk at runtime disappears on the next restart or deploy.
5. Issue a token and add the connector in claude.ai
uv run python issue_token.py --name alice --role analyst --tenant acme
Then in claude.ai: Settings → Connectors → Add custom connector
- URL:
https://anvaya-labs-mcp.onrender.com/mcp - Open Request headers (this is a beta feature — if you don't see it, it may not be rolled out to your account yet)
- Header name:
authorization - Header value:
Bearer <the token you issued>
Setup
uv sync
uv run anvaya-mcp
The 4 tools
get_database_schema(db_uri, role)execute_safe_query(db_uri, sql_query, role, tenant_id)explain_sql_query(db_uri, sql_query)export_results_format(db_uri, sql_query, role, format_type, tenant_id)
Roles
Defined in config.py under ROLE_PERMISSIONS: admin, analyst,
support, readonly_guest. Edit that dictionary to add roles, change
which tables/columns they can see, or turn tenant filtering on/off.
What got simplified from the first version
- Sync database calls instead of async (easier to read top-to-bottom)
- No decorators, dataclasses, or Enums — just dicts and functions
- Row-level tenant filtering only supports a single
tenant_idcolumn (not multiple candidate column names) - Masking is column-name-based only (no scanning cell contents for patterns like card numbers)
Connections and schema are cached (see db_engine.py — ENGINE_CACHE
and SCHEMA_CACHE, two plain dictionaries), so repeated calls reuse the
same connection instead of opening a new one every time, and don't
re-fetch the schema on every call. The schema cache refreshes itself
every 5 minutes, or immediately if you pass force_refresh=True.
Everything from your original feature list is still here — schema discovery, relationship mapping, read-only enforcement, EXPLAIN, table/column RBAC, row-level filtering, data masking, CSV/Excel/JSON export, and audit logging — just written as plainly as possible.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.