Prompts aren't permissions.
“Only run SELECT” is a request to a model, not a control. The first confident mistake lands on production data.
Universal DB MCP gives Claude Code, Cursor and any MCP agent governed, read-only access to PostgreSQL, MySQL, MariaDB, ClickHouse, Oracle, SQL Server, Db2 and SQLite. Writes through it aren't discouraged. They're refused.
Tool calls and results are real output from the project's test databases. The prompts are illustrative.
DROP TABLE.“Only run SELECT” is a request to a model, not a control. The first confident mistake lands on production data.
A filter looking for DELETE at the start of a statement never sees the one inside a CTE, behind a MySQL executable comment, or after a semicolon.
A long scan under the wrong isolation level takes share locks, and your production writes queue up behind an agent's curiosity.
Universal DB MCP closes all three, with layers that don't trust each other.
The guard refuses every write on every engine. Where the database has a read-only switch, the session refuses them too. Whatever does run is bounded, masked and audited.
Every statement becomes a syntax tree, and the guard walks all of it before anything runs.
SELECT INTO, sequence access or locking hints, even inside a CTEApplied right after connecting and read back from the server, so you can see it took effect.
Big tables stay big on the server. What comes back is capped, scrubbed and logged.
Twelve ways an agent, or a prompt injection, might try to write, lock or escape. Every verdict is the guard's real output, and a test in the repository fails if this page and the guard ever disagree.
SELECT id, name, region FROM sales.customers WHERE region = 'north' LIMIT 50
Guard policy for this demo: connection warehouse, schema allowlist sales.
29 tools turn an agent into a careful analyst. It maps, searches, profiles, documents and cross-checks your databases, and every one of those calls is read-only and bounded.
Find where a value lives across every permitted table of every connection. Case-insensitive, time-budgeted, sensitive columns skipped, and no SQL from the agent.
One call runs on many connections and merges results by column shape. A join reconciles two results from different engines inside the server, masked per connection.
Profiles each table on a bounded sample and ranks findings with their evidence. It recommends; it never changes anything.
A Markdown data dictionary from catalog metadata: types, keys, indexes, comments and relationships. Row values never appear.
Every table, column, key and index in one call, with declared types mapped to portable ones an ETL layer can build on.
EXPLAIN on PostgreSQL, MySQL, ClickHouse and SQLite. EXPLAIN PLAN on Oracle and Db2. SHOWPLAN on SQL Server. The statement is planned, not run, and EXPLAIN ANALYZE is refused whatever the configuration says. On ClickHouse, which evaluates subqueries while it plans, planning gets a 1,000-row read ceiling, or a warning where the account's profile refuses one. A MySQL TREE or JSON plan that could show a masked value is withheld, because MySQL prints the values it reads while planning.
db_list_connectionsdb_test_connectiondb_get_capabilitiesdb_list_catalogsdb_list_databasesdb_list_schemasdb_list_tablesdb_get_tabledb_list_columnsdb_list_viewsdb_list_synonymsdb_list_routinesdb_list_indexesdb_search_metadatadb_get_relationshipsdb_get_statisticsdb_validate_querydb_querydb_sample_tabledb_explaindb_get_query_historydb_get_catalogdb_profile_tabledb_search_valuesdb_infer_relationshipsdb_review_schemadb_document_schemadb_federated_querydb_federated_joinEach connector runs the same 22-check probe against real server images: catalog, keys, indexes, bounded queries, profiling, value search, query plans and the session read-back. 26 of 26 images pass.
Read-only transactions at the server, lock and statement timeouts.
Read-only transactions, lock and execution-time limits.
Same connector as MySQL, statement-time limits.
readonly profile pinned. No foreign keys, routines or composite unique indexes to check.
Thin and thick mode. Thick mode reaches accounts that only have legacy password verifiers.
READ UNCOMMITTED and a lock timeout. Plans through SHOWPLAN.
Isolation UR enforced, a lock timeout, and WITH UR accepted in statements.
Opened read-only with query_only, for local files and demos.
Oracle 12c has no redistributable test image, so it hasn't been run. SQL Server needs Microsoft ODBC Driver 18 on the machine running the server, and Oracle thick mode needs Instant Client. On ClickHouse, only the account's profile (max_memory_usage) bounds the server's own memory, so set one.
The most valuable data often lives on isolated networks. Universal DB MCP installs there from a USB stick and never phones home.
A staging machine with internet access builds one offline bundle per platform: every wheel pinned by hash, OS packages and an SBOM.
The bundle is signed with Ed25519, and every file in it is listed with its SHA-256. So is every file on the release stick, installer scripts included.
USB stick or any trusted channel. Before anything on the stick runs, the site checks its signed file list with the release key it already trusts, using the host's own openssl or the bootstrap an earlier release installed. On Ubuntu the bootstrap then copies the .deb packages to a root-only folder and checks them again, and dpkg installs those copies, never the stick's. It also refuses a stick older than the release it last installed.
The signature and every file hash are checked before anything executes. Any mismatch stops the install.
A .deb for Ubuntu 24.04 or a .pkg for macOS sets up the service; pip runs with --no-index --require-hashes.
Each upgrade builds beside the running install and keeps the previous release. One command rolls back, and from this release on the installers and the container image loader refuse to replace a newer release unless you ask for it.
Every number here comes from a test run or an evidence file in the repository.
A tool that guards your data should be straight about its own gaps. These are open, and the ledger tracks every one.
Read the full ledgerPython 3.12 and uv. Pick the drivers you need: pg, mysql, clickhouse, oracle, mssql, db2.
Nothing is fetched at runtime. For isolated networks, build a signed offline bundle instead.
$ git clone <repository-url> universal-db-mcp $ cd universal-db-mcp $ uv venv --python 3.12 .venv $ uv pip install --python .venv/bin/python \ -e '.[pg,mysql]'
An interactive wizard that tests the connection live. Credentials go to 0600 files, never into the config. No database handy? Build the demo SQLite file first and point the wizard at it.
$ .venv/bin/udbmcp add-connection# no database handy? build the demo first $ .venv/bin/python examples/sqlite-demo/create_demo.py
Detects Claude Code, Claude Desktop, Cursor, VS Code and Cline, and asks before writing any config. Restart the agent and you're in.
$ .venv/bin/udbmcp configure-agentsList my databases, then review the largest schema and document it.Air-gapped install guide
Not through the server. There is no write mode: the configuration rejects security.allow_write_operations: true, security.read_only: false and a connection's read_only: false, no tool writes your data, and every statement an agent sends goes through the guard, which only accepts reads. On engines with a server-side switch, the session refuses writes as well. Query plans are the one thing written, and never into your tables: on Db2, db_explain has EXPLAIN PLAN write plan rows into the explain tables a DBA provisions and deletes them again, and on Oracle it writes to the session-private PLAN_TABLE and deletes its rows. The statement being planned has passed the guard and is never executed. One caveat: in stdio mode the server runs as your user, so an agent that can also run shell commands could read the stored credentials and connect on its own. Give each connection a SELECT-only login (on Db2, plus INSERT, SELECT and DELETE on the explain tables if you want plans), or run the server over HTTP under a service account.
Do that too. A read-only account stops writes, but it doesn't stop a long scan from taking share locks, cap how much data comes back, mask sensitive columns, keep the agent to the schemas you chose when the account can see more, or leave an audit record per call. The server does all of that.
Not because of this server. It never calls an LLM, has no telemetry and downloads nothing at runtime. Query results go to the MCP client you connected, and that client decides what reaches its model.
Any MCP client over stdio or streamable HTTP. udbmcp configure-agents registers it with Claude Code, Claude Desktop, Cursor, VS Code and Cline, and asks before it writes any config file.
A SELECT-only login that can read the schemas you list (on SQL Server, db_datareader plus SHOWPLAN, never db_owner). Nothing is installed on the server. SQL Server needs Microsoft ODBC Driver 18 on the machine running Universal DB MCP, Oracle thick mode needs Instant Client, Db2 query plans need explain tables a DBA creates once, with INSERT, SELECT and DELETE on them for the login, and a ClickHouse account needs a settings profile with max_memory_usage, the only bound on the server's own memory.
It stops the value coming back in a result, wherever the statement moves it: aliases, CTEs, UNIONs, joins and derived tables are traced, and a statement whose shape can't be checked is refused before it runs. Views that show other sessions' SQL (process lists, statement caches, audit trails) are refused on every connection, whatever system schemas you open, because their statement text and bind values would carry what masking hides. So are column statistics (histograms, low and high values) and stored credentials. It doesn't stop inference: a WHERE, ORDER BY or GROUP BY on a masked column can still reveal what it holds. For columns that must stay secret, use column-level grants or a view without them. Masking is the second line.
Install the .deb or .pkg, which sets it up as a service, and serve it over HTTP with a bearer token behind your TLS proxy. Database credentials then live on that host, never on the developers' machines.
It is tested against 26 server images, 12,548 automated tests and no-network package gates for Ubuntu and macOS, and it has been through separate correctness and security reviews; the ledger records what the latest review's 95 findings changed and what stays open. The Windows installer isn't verified yet, the version matrix and package gates are due a re-run on this build, and the ledger lists everything else that isn't verified.
Give your agents the whole picture of your data, without handing them the keys.