Skip to main content
Glama
OmniSQL MCP

OmniSQL MCP

by kylepantall

Hopsql

CI MIT license

Give Claude Code, Codex and OpenCode read-only access to the databases you already use — including the ones behind bastions. Hopsql reuses your saved DBeaver connections, follows their SSH jump hosts (or AWS SSM), and queries with native drivers.

Hopsql is a fork of omnisql-mcp by Sarthak Jain, based on its v3.0.0 release. It is maintained separately, is not published to npm, and installs straight from this repo. Thanks to the omnisql-mcp authors and contributors for the foundation. See what's different.

Quick setup · Features · Docs · Changelog

What's different from omnisql-mcp

Area

Hopsql

SSH jump hosts

Follows DBeaver's jump-server chain, checking every host key along the way.

AWS SSM

Reaches bastions with no public SSH, over Session Manager (as an SSH transport or a direct port forward).

SSH agents

Finds your agent automatically, including the 1Password SSH agent, on macOS, Linux and Windows.

Reliability

Dropped tunnels reconnect on the same local port, pools rebuild, and read-only queries retry once.

Postgres TLS

No sslmode behaves like DBeaver (prefer): TLS first, plaintext only if the server has none.

Dumps and exports

New dump_table / dump_database (via pg_dump / mysqldump) and streaming export_data for large results.

Manage UI

hopsql in a terminal: make a connection read-only, or add an AWS SSM hop and Secrets Manager login, without editing JSON.

Install

One command from GitHub for macOS, Linux and Windows; no npm package.

Names

hopsql binary and MCP entry, HOPSQL_* settings. Legacy OMNISQL_* settings still work.

Related MCP server: MCP Database Server

What you can do

Capability

How it helps

Reach databases behind bastions

Use DBeaver's saved SSH tunnels and jump hosts as-is, or add AWS SSM hops.

Reuse saved connections

Read database and SSH settings from DBeaver-compatible workspaces, including custom projects.

Query across engines

PostgreSQL, MySQL/MariaDB, SQLite, SQL Server, Oracle, DuckDB, and ClickHouse.

Choose another database

Discover databases and select one at call time, using the same saved server credentials.

Understand your data

Browse tables, inspect columns, explain queries, export CSV/JSON, and compare schemas.

Control access

Choose read-only mode, restrict connections, or disable tools.

Set up your client

One guided command for Claude Code, Codex, and OpenCode.

Database Support

Supported execution paths:

  • PostgreSQL (via pg)

  • MySQL / MariaDB (via mysql2)

  • SQL Server / MSSQL (via mssql)

  • SQLite (via sqlite3 CLI)

  • ClickHouse (HTTP/HTTPS with keep-alive and zstd/gzip; no external client)

  • DuckDB (via DuckDB CLI 1.5.6+; existing local files, locked safe mode, exact numeric output)

  • Oracle (via oracledb)

Postgres-compatible (routed through pg driver automatically):

  • CockroachDB, TimescaleDB, Amazon Redshift, YugabyteDB, AlloyDB, Supabase, Neon, Citus

Other databases: Unsupported drivers return an explicit error. External GUI/CLI query fallback has been removed so access and output policies remain enforceable.

DuckDB uses an installed CLI so its native binary stays out of the npm package. Install it with brew install duckdb on macOS, or use the official downloads. Set HOPSQL_DUCKDB_CLI if the executable is outside your MCP client's PATH. See database support for configuration and limits.

Custom drivers wrapping any of the above are detected automatically — see Custom and IAM-Authenticated Drivers.

Requirements

  • macOS, Linux or Windows. The installer provides Bun 1.4.3+ if you don't have it; the built server also runs on Node.js 22.15+ or 24+.

  • A database connection or an existing DBeaver-compatible workspace

  • Per feature, a few command-line tools; hopsql doctor shows which you have and need

  • For dump_* tools: pg_dump (brew install libpq / winget install PostgreSQL.PostgreSQL) or mariadb-dump/mysqldump (brew install mariadb-connector-c or mysql-client / winget install MariaDB.Server)

Quick setup

One command installs and registers it with Claude Code; no clone, Node.js or Bun needed. To upgrade, run it again without --claude / -Claude.

macOS / Linux

curl -fsSL https://raw.githubusercontent.com/kylepantall/hopsql/main/scripts/install.sh | bash -s -- --claude

Windows (PowerShell)

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/kylepantall/hopsql/main/scripts/install.ps1))) -Claude

What it does

macOS / Linux

Windows

Downloads and builds this repo

~/.local/share/hopsql

%LOCALAPPDATA%\hopsql

Launcher

~/.local/bin/hopsql

%LOCALAPPDATA%\hopsql\bin\hopsql.cmd

Runtime

Your Bun 1.4.3+, or a private checksum-verified copy

Same

--claude / -Claude

Registers with Claude Code (user scope); stops if a hopsql or legacy omnisql entry exists

Same

--force / -Force

With --claude, replaces that entry; its env (allowlist, config file) is not kept

Same

Leave out --claude / -Claude to install only. Pin a branch, tag or commit with bash -s -- --claude <ref> or -Ref <ref>. HOPSQL_INSTALL_DIR and HOPSQL_BIN_DIR choose other directories. Start a new Claude session after setup.

Guided setup and other clients

After installing, run the guided installer from the launcher to pick Claude Code, Codex or OpenCode and choose connections:

hopsql install

It registers the installed launcher, never the upstream npm package. The installer detects clients and offers direct database setup, an existing Hopsql config, or selected DBeaver connections. Add multiple instances to one MCP server, each with its own read-only setting and table rules. Direct setup uses verified TLS by default; passwords are masked and saved only in a private local config (0600 on Unix), or referenced through environment variable names. No Hopsql API key is needed. An agent with unrestricted file access can still read local config files. Start a new client session after setup.

To add it to a specific client directly:

hopsql install claude
hopsql install codex
hopsql install opencode

Registrations default to read-only. install <client> opens guided setup in a terminal. For noninteractive setup, provide --config /path/to/connections.json, or --workspace /path/to/workspace --allow dev,analytics for selected saved connections. Explicit config excludes workspace discovery. --dry-run previews registration. An existing hopsql entry is kept unless you confirm replacing it in guided setup or pass --replace (Claude Code and Codex; remove OpenCode entries manually). Setup never writes through symlinks.

--allow-writes enables write tools. Direct JSON connections also need readOnly: false; imported connections retain their saved flag. Database grants and operator policy still apply. SSH requires a verified known_hosts entry by default; HOPSQL_SSH_STRICT_HOST_KEY=false explicitly allows unknown hosts for legacy setups.

Native client commands

You can also register the server using your client's own CLI:

# Claude Code — available across projects
claude mcp add --transport stdio --scope user hopsql --env HOPSQL_CONFIG_FILE=/absolute/path/connections.json -- ~/.local/bin/hopsql

# Codex
codex mcp add hopsql --env HOPSQL_CONFIG_FILE=/absolute/path/connections.json -- ~/.local/bin/hopsql

# OpenCode v2 — available across projects
opencode mcp add hopsql --global -- ~/.local/bin/hopsql

On Windows, use cmd /c %LOCALAPPDATA%\hopsql\bin\hopsql.cmd as the command.

These follow the Claude Code, Codex, and OpenCode v2 registration commands. OpenCode v1 users can add a local server through their MCP settings.

Claude Desktop and Cursor

Add the following MCP entry to Claude Desktop's claude_desktop_config.json, or Cursor's mcp.json:

{
  "mcpServers": {
    "hopsql": {
      "command": "/Users/you/.local/bin/hopsql",
      "env": { "HOPSQL_CONFIG_FILE": "/absolute/path/connections.json" }
    }
  }
}

Use the absolute launcher path the installer prints. On Windows, use "command": "cmd" and "args": ["/c", "C:\\Users\\you\\AppData\\Local\\hopsql\\bin\\hopsql.cmd"].

Manage connections

Run hopsql (or hopsql manage) in a terminal to pick a connection and:

Action

Effect

Access: read-only / ask / writable

Per-connection writes: refused, approved by you in the client one statement at a time, or allowed

Change access for several connections

The same, for a multi-selection

Set up an AWS SSM hop

Bastion by Name tag or instance ID, remote host/port, optional Secrets Manager login

Remove the AWS SSM hop

Back to the connection's own settings

Dump tools and folder

Shows the pg_dump / mariadb-dump / mysqldump the server will use (with versions), lets you pin one, and sets where saved dumps go

Changes are saved to ~/.config/hopsql/overrides.json (HOPSQL_OVERRIDES_FILE to move it) and apply on the next call; no restart or re-registration. They win over overrides in HOPSQL_CONFIG_FILE.

⚠️ Access set here also wins over HOPSQL_READ_ONLY=true, which now only covers connections left at their default. Policy-file readOnly rules still always apply. Write tools appear in the client's tool list as soon as any connection can take writes (the server sends tools/list_changed).

Bulk changes from a script or shell:

hopsql access                                # list connections and their access
hopsql access ask prod-db reporting          # by id or name
hopsql access read-only --all
hopsql access reset staging                  # back to the connection's default

ask prompts in the MCP client for each write_query, create_table, alter_table, drop_table and write statement in a transaction, showing the SQL. An approval covers that one call only. Clients that can't prompt are refused, and so is hopsql query --write. hopsql exec asks once per run instead (see below). A model that has a shell can run hopsql access itself, so ask protects against MCP-only clients, not a model with terminal access. MCP clients start Hopsql with piped stdio, so they still get the server; hopsql serve forces it in a terminal.

Dumps

dump_table / dump_database find the dump client themselves: HOPSQL_PG_DUMP_PATH / HOPSQL_MYSQLDUMP_PATH, then a client pinned in hopsql manage, then the newest one on PATH or in the usual install folders (Homebrew libpq/postgresql@N/mysql-client/mariadb, Postgres.app, Program Files). A newer pg_dump can dump older servers, never the reverse.

Pass saveToFile: true to write the dump to a new owner-only file in the dump folder (default ~/hopsql-dumps; HOPSQL_DUMP_DIR or hopsql manage to change) and get its path back, instead of a read_export handle. fileName picks the name; existing files are never replaced. Saved dumps are capped by HOPSQL_DUMP_FILE_MAX_BYTES (default 8 GiB), not the 32 MiB artifact limit.

Command line

Command

What it does

hopsql query <conn> --file report.sql

Runs one statement from a .sql/.psql/.pgsql/.mysql/.ddl/.dml file (max 1 MiB) through execute_query, with the same policy and JSON output. Inline SQL works too: hopsql query <conn> "SELECT 1"

hopsql query <conn> --write --file fix.sql

The same through write_query; needs HOPSQL_READ_ONLY=false and a writable connection

hopsql exec <conn> -- psql -c 'select 1'

Runs a local tool with the connection's credentials in its environment (PG* or MYSQL_HOST/MYSQL_TCP_PORT/MYSQL_USER/MYSQL_PWD, plus DATABASE_URL), through the same SSH/SSM tunnel

hopsql doctor

Lists the command-line tools Hopsql uses (sqlite3, duckdb, pg_dump, mysqldump/mariadb-dump, aws, session-manager-plugin): found with version, or missing with the install command for your OS. Tools your connections need are marked required; --strict exits 1 if one is missing, --json for scripts. The installers run it at the end

hopsql update

Checks GitHub for a newer release and reruns the installer for it (--check only reports, --yes skips the prompt, --json for scripts)

hopsql refresh

Recycles running MCP servers (pooled connections, tunnels and cached config dropped; the next call reconnects) and stops ones older than the installed build, so clients start the new version on reconnect. The refresh tool lets a model do the same. macOS and Linux

The CLI reads the same HOPSQL_* variables as the server, so export HOPSQL_CONFIG_FILE (and any allowlist) in your shell if your MCP entry sets them.

exec is for PostgreSQL and MySQL/MariaDB connections. It refuses read-only connections, because raw credentials bypass Hopsql's SQL policy. On ask connections it asks you first, showing the connection and the full command: in the terminal when there is one, otherwise in a desktop dialog (macOS dialog, zenity/kdialog on Linux, a Windows message box). One approval covers the whole run, since Hopsql can't see the statements the command sends. With no terminal and no desktop, it refuses. Model-driven shells get piped output, so the password is masked there as ********. It still stops accidental leaks only: a command that deliberately encodes the password could get it out.

execute_query and write_query take a file path instead of query too, so a model can run a SQL file without pasting it.

Updates

The server checks GitHub releases at startup, at most once a day, and prints a notice on stderr when a newer one exists (HOPSQL_UPDATE_NOTIFIER=false turns this off). Models can call check_for_update, then update_hopsql. The latter asks you to confirm in the client before downloading anything, and refuses clients that can't ask. Updates only apply to copies installed by install.sh/install.ps1. Restart your MCP clients afterwards.

Releasing: bump version in package.json (and move the CHANGELOG's Unreleased notes under it) in a PR. Merging it to main tags v<version> and publishes the GitHub release, which installs then pick up. Pushing a v* tag by hand works too, as long as it matches package.json.

One server, many instances

Register Hopsql once. Select connectionId in each tool call; select database to switch databases on PostgreSQL, MySQL/MariaDB, SQL Server, or ClickHouse. Each instance can have its own read-only setting, table policy, credentials, timeout, row/byte limits, and pool size.

Set HOPSQL_CONFIG_FILE to your JSON configuration, or reuse discovered workspace connections. Explicit connections default to read-only. See the multi-instance configuration guide and access policies.

Large results use private, expiring handles with row and column pagination. Long cells and large exports can be read in bounded chunks. See result paging.

Configuration

Environment Variables

Variable

Description

Default

HOPSQL_DISCOVER_WORKSPACE

Include saved workspace connections

false with a config file; true otherwise

HOPSQL_CONFIG_FILE

JSON configuration for multiple database instances and their settings

Unset

HOPSQL_POLICY_FILE

Additional schema, table, function, and database access rules

Unset

HOPSQL_WORKSPACE

Path to local DB client workspace directory

OS default

HOPSQL_PROJECT

Restrict discovery to one DB client project/workspace folder

All projects

HOPSQL_TIMEOUT

Query timeout (ms)

30000

HOPSQL_DEBUG

Enable debug logging

false

HOPSQL_UPDATE_NOTIFIER

Check GitHub releases at startup and show notices on stderr

true

HOPSQL_REPO

GitHub repository for update checks and hopsql update

kylepantall/hopsql

HOPSQL_UPDATE_GITHUB_URL / HOPSQL_UPDATE_RAW_URL

Origins for release checks and installer downloads (a mirror or test fixture)

https://github.com / https://raw.githubusercontent.com

HOPSQL_READ_ONLY

Disable all write operations

true

HOPSQL_ALLOWED_CONNECTIONS

Comma-separated whitelist of connection IDs or names

All

HOPSQL_DISABLED_TOOLS

Comma-separated tools to disable

None

HOPSQL_POOL_MIN

Minimum connections per pool

0

HOPSQL_POOL_MAX

Maximum connections per pool

4

HOPSQL_POOL_IDLE_TIMEOUT

Idle connection timeout (ms)

30000

HOPSQL_POOL_ACQUIRE_TIMEOUT

Connection acquire timeout (ms)

10000

HOPSQL_AWS_CLI_PATH

Path to the AWS CLI (RDS IAM authentication and SSM hops)

aws

HOPSQL_IAM_TOKEN_TIMEOUT

Timeout for minting an RDS IAM auth token (ms)

20000

HOPSQL_SSH_KNOWN_HOSTS

known_hosts file used to verify SSH tunnel hosts

~/.ssh/known_hosts

HOPSQL_SSH_STRICT_HOST_KEY

Refuse SSH tunnel hosts with no known_hosts entry

true

HOPSQL_SSH_AUTH_SOCK

SSH agent socket or pipe; checked before SSH_AUTH_SOCK

Discovered

HOPSQL_ARTIFACT_QUOTA_BYTES

Disk quota for stored results, exports and dumps

67108864 (64 MiB)

HOPSQL_EXPORT_MAX_ROWS

Row cap for streamed PostgreSQL/MySQL exports

5000000

HOPSQL_EXPORT_MAX_BYTES

Uncompressed byte cap for streamed exports (≤ quota)

33554432 (32 MiB)

HOPSQL_EXPORT_TIMEOUT_MS

Timeout for a streamed export (ms)

300000

HOPSQL_DUMP_MAX_BYTES

Uncompressed byte cap for dump_* output (≤ quota)

33554432 (32 MiB)

HOPSQL_DUMP_TIMEOUT_MS

Timeout for a dump; the client is killed after it (ms)

600000

HOPSQL_PG_DUMP_PATH

pg_dump binary for dump_* tools

pg_dump on PATH

HOPSQL_MYSQLDUMP_PATH

mariadb-dump/mysqldump binary for dump_* tools

PATH (mariadb-dump first for MariaDB)

Read-Only Mode

Enabled by default and blocks all write operations. The execute_query tool only allows SELECT, EXPLAIN, SHOW, and DESCRIBE statements. Transaction tools are disabled entirely.

{
  "mcpServers": {
    "hopsql": {
      "command": "/Users/you/.local/bin/hopsql",
      "env": {
        "HOPSQL_READ_ONLY": "true"
      }
    }
  }
}

Connection Whitelist

Restrict which workspace connections are visible. Accepts connection IDs or display names, comma-separated:

{
  "mcpServers": {
    "hopsql": {
      "command": "/Users/you/.local/bin/hopsql",
      "env": {
        "HOPSQL_ALLOWED_CONNECTIONS": "dev-postgres,staging-mysql"
      }
    }
  }
}

Disable Specific Tools

{
  "mcpServers": {
    "hopsql": {
      "command": "/Users/you/.local/bin/hopsql",
      "env": {
        "HOPSQL_DISABLED_TOOLS": "drop_table,alter_table,write_query"
      }
    }
  }
}

Available Tools

Connection Management

  • list_connections - List all database connections

  • list_databases - Discover accessible databases on PostgreSQL, MySQL/MariaDB, SQL Server, and ClickHouse

  • get_connection_info - Get connection details

  • test_connection - Test connectivity

Data Operations

  • execute_query - Run read-only queries (SELECT, EXPLAIN, SHOW, DESCRIBE only), inline or from a file

  • write_query - Run INSERT/UPDATE/DELETE, inline or from a file

  • run_script - Run a multi-statement script (a migration), inline or from a file, in one transaction: all statements commit or none do. ask connections approve the whole script once

  • export_data - Export to CSV/JSON, with optional gzip, Brotli, or zstd

  • read_result - Read a page of stored rows and columns

  • read_result_cell - Read a long cell in chunks

  • read_export - Read a stored export in bounded base64 chunks

  • dump_table - Dump listed tables as SQL (schemaOnly/dataOnly) via pg_dump or mariadb-dump/mysqldump

  • dump_database - Dump a whole database, or an include list of tables, the same way

PostgreSQL and MySQL/MariaDB exports stream straight to a private file, so maxRows can go up to HOPSQL_EXPORT_MAX_ROWS; results of 64 KiB or less still return inline. Other engines keep the buffered 1,000,000-row cap.

Dumps are read-only and work in read-only mode. They need the database client installed (brew install libpq or brew install mariadb/mysql-client; Windows: winget install PostgreSQL.PostgreSQL or winget install MariaDB.Server). They connect through SSH tunnels and the saved TLS mode, and pass passwords by environment or a private temporary option file, never argv. When a table policy applies, dump_database requires an explicit tables list. Failures return isError with a stable error code (DUMP_TOOL_MISSING, DUMP_TIMEOUT, DUMP_OUTPUT_LIMIT, DUMP_FAILED, …).

Exports support optional gzip, Brotli, and zstd downloads through export_data.compression. Ordinary queries remain paginated JSON. Measured compression and media changes.

Schema Management

  • list_tables - List tables and views

  • get_table_schema - Get columns, indexes, and constraints

  • get_table_stats - Get catalog row estimates and data/index storage

  • create_table - Create tables

  • alter_table - Modify tables

  • drop_table - Drop tables (requires confirmation)

Transactions

PostgreSQL, MySQL/MariaDB, and SQL Server support explicit transactions. Results obey the same row/byte limits and pagination as ordinary queries. Each transaction accepts one operation at a time; a failed query or changed connection/access policy rolls it back. Schema operations are excluded because some engines commit DDL implicitly. At most 32 transactions may be active or starting; idle transactions expire after one hour.

  • begin_transaction - Start a new transaction

  • execute_in_transaction - Execute query within a transaction

  • commit_transaction - Commit a transaction

  • rollback_transaction - Roll back a transaction

run_script uses the same transaction path. It adds DDL on tables, indexes, views, sequences and types where DDL rolls back (PostgreSQL, SQL Server; not MySQL/MariaDB). Functions, triggers, roles and extensions are refused, because they run or grant things the checks can't see. On ask connections the approval shows the whole script, never shortened; a script too long to show must be split into several calls. A wrapping BEGIN/COMMIT in the script is optional and dropped. Statements are split at top-level ;, so procedural bodies must be dollar-quoted (DO $$ ... $$); MySQL DELIMITER and SQL Server GO are not supported. PostgreSQL DO blocks also work in execute_in_transaction. Their body can't be checked, so they are refused on connections with access policies.

Query Analysis

  • explain_query - Analyze query execution plan

  • compare_schemas - Compare schemas between two connections

  • get_pool_stats - Get connection pool statistics

Other

  • get_database_stats - Database statistics

  • append_insight - Store analysis notes

  • list_insights - Retrieve stored notes

  • check_for_update - Compare this install with the latest GitHub release

  • update_hopsql - Install the latest release after the user confirms in the client

  • refresh - Drop pooled connections, tunnels and cached config; recycle other servers and stop outdated ones

Security

  • Database permissions: use a database account with read-only grants when you require a database-level permission boundary. The SQL checks are safeguards, not a full SQL sandbox.

  • Read-only enforcement: execute_query only accepts read-only statements (SELECT, EXPLAIN, SHOW, DESCRIBE, PRAGMA). Write operations must use write_query.

  • Query validation: Blocks DROP DATABASE, DROP SCHEMA, TRUNCATE, DELETE/UPDATE without WHERE, GRANT, REVOKE, and user management statements.

  • Connection whitelist: Restrict which connections are exposed via HOPSQL_ALLOWED_CONNECTIONS.

  • Tool filtering: Disable any tool via HOPSQL_DISABLED_TOOLS.

  • Input sanitization: Connection IDs and SQL identifiers are sanitized to prevent injection.

  • Recommendation: For production use, also use a database-level read-only user for defense in depth.

Workspace Format Support

Supports both configuration formats written by DBeaver-compatible DB clients:

  • Legacy: XML config in .metadata/.plugins/org.jkiss.dbeaver.core/

  • Modern: JSON config in General/.dbeaver/

The project/workspace folder name (General by default) is configurable via HOPSQL_PROJECT, so workspaces using a custom or renamed DBeaver project (e.g. DataPlatform) are discovered without needing to rename the project or symlink the folder.

Connection modes

DBeaver connections are configured either manually (host, port, database fields) or by URL (a JDBC URL). Both work. In URL mode DBeaver leaves the host/port fields at placeholder values — usually localhost — and reads only the URL, so the URL is what is used here too.

SSH tunnels

Connections that DBeaver reaches through an SSH tunnel are tunneled here as well. The tunnel is opened on first use and reused for the lifetime of the server, with a loopback-only local forward, and the connection's host/port are treated the way DBeaver treats them: as the database as seen from the SSH server.

  • Agent, password and public-key authentication are supported, taken from the connection's SSH tab. Credentials saved in the workspace (including the tunnel's own, stored separately from the database credentials) are decrypted and used.

  • The SSH agent is found in this order: HOPSQL_SSH_AUTH_SOCK, SSH_AUTH_SOCK, IdentityAgent in ~/.ssh/config (none disables it), then the 1Password agent socket. On Windows the OpenSSH agent pipe (also used by 1Password) and Pageant follow. MCP clients usually do not inherit your shell, so the config and 1Password fallbacks matter there. Key authentication also offers agent identities, and uses the agent alone when the key file is missing.

  • A dropped tunnel (sleep, network change) reopens on the same local port when it is free, and pools are rebuilt. Read-only queries retry once after a connection-level failure; writes and transactions never retry.

  • Bastions without public SSH can be reached over AWS SSM. DBeaver has no fields for it, so declare it in HOPSQL_CONFIG_FILE, under overrides (keyed by connection id or name; set HOPSQL_DISCOVER_WORKSPACE=true too) or on a configured connection. mode: "ssh" carries the first SSH hop over the session; mode: "port-forward" skips SSH and forwards straight to the database host. Needs the AWS CLI and session-manager-plugin.

{
  "version": 1,
  "connections": {},
  "overrides": {
    "Reporting (prod)": {
      "ssm": { "target": "i-0123456789abcdef0", "mode": "ssh", "region": "eu-west-2", "profile": "prod" }
    }
  }
}
  • To skip or replace DBeaver's jump servers without editing DBeaver, add an ssh override (same places as ssm, including the managed ~/.config/hopsql/overrides.json). It holds addresses and users only; authentication still comes from DBeaver or the SSH agent.

ssh override

Effect

{ "jumpHosts": [] }

Drop DBeaver's bastions; dial the final SSH host directly

{ "jumpHosts": [{ "host": "10.0.0.5", "port": 22, "user": "jump" }] }

Replace the bastions, outermost first

{ "host": "app.example.com", "port": 22, "user": "ec2-user" }

Replace the final SSH host (adds a tunnel to a direct connection)

{ "enabled": false }

No tunnel; connect to the database host directly

{ "enabled": true }

Turn on a tunnel DBeaver has switched off

  • The final host keeps DBeaver's auth. A replacement bastion keeps the auth of a DBeaver hop with the same host, else uses the agent; its user defaults to the tunnel's.

  • With ssm mode: "ssh" the session carries the first hop of the resulting route; enabled: false is refused there. ssm mode: "port-forward" already skips SSH, so ssh is refused with it. A vpn probes, or a docker VPN dials, the resulting first hop.

  • SSH host keys must match a trusted entry in known_hosts; unknown hosts are refused by default. Verify the host fingerprint through a trusted channel before adding it. HOPSQL_SSH_STRICT_HOST_KEY=false allows unknown hosts explicitly; known-host mismatches still fail.

  • If a tunnel cannot be opened the connection fails with that reason. It never falls back to connecting directly to the recorded host, which would reach an unrelated local database.

Table policies resolve real catalog names before checking access, including engine-specific case rules. Qualified denies also cover unqualified SQL; paged results and exports recheck permissions on every read. Restricted queries stay inside the selected database. See access rules for configuration and limits.

VPNs

A connection can bring a VPN up before it dials, so you don't have to connect by hand. hopsql drives your own VPN client. It checks whether the connection's first host (the outermost SSH hop, else the database) accepts a TCP connection. If not, it starts the VPN and waits up to connectTimeoutMs (default 60s) for that host. A VPN hopsql started is taken down when hopsql exits (disconnectOnExit: false keeps it up).

OpenVPN Connect (macOS, Windows):

hopsql vpn import ~/Downloads/work.ovpn --name Work   # once; save credentials in the app or use an autologin profile
hopsql vpn use Work "Reporting (prod)" orders-db       # profile id or name, then connections
hopsql vpn list                                        # profiles, and which connections use a VPN
hopsql vpn clear orders-db

Only hopsql through the VPN (Docker): add --docker and the profile runs in a local container instead. Your Mac's routing is untouched, so the browser and other apps stay off the VPN. hopsql dials through the container's SOCKS proxy (published on loopback only), both for direct connections and for the first hop of an SSH tunnel. Needs Docker running. The image is built locally on first use from a digest-pinned Alpine base with openvpn and dante. Certificate-based profiles only (no password, SAML or MFA prompts). Not available with SSM.

hopsql vpn use Work orders-db --docker              # an imported OpenVPN Connect profile
hopsql vpn use ~/vpn/work.ovpn orders-db --docker   # or any .ovpn file

Any other client: give the argv to bring it up and down (no shell), plus an optional check whose exit status 0 means "up". Set it under overrides or on a configured connection:

"overrides": {
  "orders-db": {
    "vpn": { "provider": "command", "up": ["wg-quick", "up", "work"], "down": ["wg-quick", "down", "work"] }
  }
}

⚠️ Caveat

Why

The VPN is machine-wide (except --docker)

It changes routing for every app, not just hopsql

The Docker proxy is reachable from your machine

Any local process can use 127.0.0.1:<port> to reach the VPN while the container runs

OpenVPN Connect holds one profile at a time

Connections that need different profiles will drop each other's VPN

A database that's down looks like the VPN is down

hopsql starts the VPN, then times out with a message that says so

Several hopsql servers share one VPN

The server that started it disconnects it when it exits

Querying another database on the same server

Use list_databases with a saved connectionId to discover databases accessible on a PostgreSQL, MySQL/MariaDB, SQL Server, or ClickHouse instance. Pass an optional database to execute_query, export_data, dump_table, dump_database, explain_query, list_tables, get_table_schema, get_database_stats, test_connection, or get_pool_stats:

{"connectionId": "my-pg-server", "database": "app_logs", "query": "SELECT count(*) FROM log"}

The saved host, credentials, IAM, TLS, and SSH settings are reused. The saved connection is unchanged and pools remain separate for each database. The existing connectionId: "my-pg-server/app_logs" shorthand also works. File-backed engines such as SQLite require a separate saved connection for each file. Read-only checks and connection whitelists still apply; list a connection ID to allow its databases, or connectionId/database entries to restrict access to specific databases.

Oracle

Oracle runs through oracledb in Thin mode, so no Oracle Client is needed. Service names, SIDs, TNS aliases and connect descriptors are read from the connection. Rows are capped by the driver, using a bounded ResultSet fetch. Ordinary queries reuse an isolated, bounded pool; privileged sessions remain standalone. Explicit multi-call Oracle transactions are not available.

Custom and IAM-Authenticated Drivers

Custom drivers

Native routing normally keys off the driver id (postgres-jdbc, mysql8). Custom drivers often use an opaque id instead — a UUID, say — which names no engine. Those connections are resolved by falling back to the connection's provider (postgresql, mysql, …) and then to the JDBC URL's sub-protocol, including wrapped ones such as jdbc:aws-wrapper:postgresql://…. A custom driver wrapping a supported engine therefore works with no extra configuration.

If an engine still cannot be identified, the resulting error names both the driver id and the provider so you can see what was missing.

AWS RDS IAM authentication

Connections that authenticate with an RDS IAM token instead of a stored password are detected and handled automatically. Both shapes are recognised:

  • AWS Advanced JDBC Wrapper drivers, which record wrapperPlugins: "iam" alongside awsProfile and iamRegion.

  • The DB client's own AWS IAM auth models.

For these connections Hopsql:

  1. Mints a token with aws rds generate-db-auth-token (via the AWS CLI, so SSO and role-chained profiles work as configured) and uses it as the password.

  2. Caches each token for 13 minutes, under its 15-minute lifetime, and re-mints per physical connection so long-lived pools keep working.

  3. Forces TLS, which RDS requires for IAM tokens.

  4. Resolves the database username from the connection when present. Where it is absent, the username is derived from your AWS identity: either the per-developer role name (<profile>-<user>) or the assumed SSO session name.

Requirements: the AWS CLI on PATH (or HOPSQL_AWS_CLI_PATH), a valid session for the connection's profile (aws sso login --profile <profile>), and network reachability to the endpoint. An expired SSO session produces an error naming the profile to re-authenticate.

Try the demo

The recording above captures a real Codex CLI session calling Hopsql tools. It uses synthetic customers and orders from the isolated .demo/ workspace. The integration script below creates the SQLite fixtures, then checks discovery, schema inspection, queries, exports, query plans, schema comparison, and blocked writes.

bun install --frozen-lockfile
bun run build
bun run demo

To also test PostgreSQL database discovery, database selection, and pool identities against a temporary local cluster:

HOPSQL_DEMO_PG_BIN=/path/to/postgres/bin bun run demo -- --postgres

The PostgreSQL cluster binds to loopback on a temporary port, uses a random password, and is stopped and deleted after the run. The SQLite examples stay under .demo/ so you can connect a client to them. Existing workspaces are untouched.

Updates

Rerun the install command to update to the latest main, then restart your MCP client; running servers keep their current version until restarted.

Set HOPSQL_UPDATE_NOTIFIER=true to get a stderr notice, at most once a day, when upstream omnisql-mcp publishes a newer npm release. The check sends no database settings or credentials.

Pulling upstream fixes

Hopsql started from omnisql-mcp commit 5eb6f78 (v3.0.0 plus docs updates) with a fresh history, so upstream changes are applied as a patch rather than merged:

git remote add upstream https://github.com/srthkdev/omnisql-mcp.git
git fetch upstream
git diff 5eb6f78 upstream/main | git apply -3

Resolve any conflicts, rename new omnisql/OMNISQL_ references to hopsql/HOPSQL_, then record the new upstream commit here as the next base.

Development

Bun 1.4.3 is the development runtime and package manager. Builds transpile with Bun; bun run typecheck remains required because transpilation does not check types. The built JavaScript also runs on Node 22.15+ and 24+.

git clone https://github.com/kylepantall/hopsql.git
cd hopsql
bun install --frozen-lockfile
bun run build
bun run test
bun run lint

To install your working copy instead of GitHub main, run HOPSQL_SOURCE_DIR="$PWD" bash scripts/install.sh (or set HOPSQL_SOURCE_DIR before scripts/install.ps1).

Releases

CI builds with Bun 1.4.3, runs the Bun tests, verifies the packed server on Bun and Node.js 22/24/26, and checks dependencies. Pushing a vX.Y.Z tag runs the release workflow, which attaches a packed archive to a GitHub release. Nothing is published to npm. Update the version in package.json and the changelog first.

License

MIT. Copyright © 2025 Sarthak Jain (omnisql-mcp) and © 2026 Kyle Pantall (Hopsql). See LICENSE.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides Claude Desktop with secure access to multiple database connections, allowing users to query MySQL, PostgreSQL, SQLite, and SQL Server databases directly through natural language.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude Code to securely interact with PostgreSQL, MySQL, SQLite, and SQL Server databases, featuring read-only mode, query validation, SSH tunneling, and field redaction for production-safe data access.
    4
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables AI assistants to interact with multiple SQL databases (PostgreSQL, MySQL, SQL Server, SQLite, Trino) through MCP, reusing existing DBeaver connections for queries, schema management, and transactions, with SSH tunneling and read-only mode support.
    22
    258 npm
    MIT