QueryMoat for VS Code
Formerly QueryDock. Same extension, new name. Your Why QueryMoat?AI coding agents write better code when they can see your real schema and data, but letting an agent run SQL against your database is risky. QueryMoat gives the agent what it needs and nothing more:
And for you, a complete database client inside the editor:
Free and ProQueryMoat is free to use, including at work, and everything that keeps your data safe stays free. Pro adds control over what agents do and a record of what they did: a lifetime licence for $14.99 once per developer, or $4.99 for the first 500 buyers. Get Pro on querymoat.com, then run QueryMoat: Enter Pro Licence Key.
Supported Databases
Future releases will expand support to MongoDB, DuckDB, and ClickHouse. Requirements
Platform SupportRuns anywhere VS Code runs: macOS (Intel & Apple Silicon), Windows (x64 & ARM64), Linux (x64, ARM64, ARMhf, Alpine), and remote/WSL/Dev Container workspaces. Quick Start
Moving from QueryDockQueryMoat is the new name of QueryDock. Install QueryMoat, then uninstall QueryDock: running both makes them overwrite each other's MCP server file. Nothing else is required. QueryMoat still:
When convenient:
Permissions you granted in QueryDock (Allow Writes on a remote database, and allowing agent writes) do not carry over; grant them again if you still need them. Zero-Config DiscoveryQueryMoat automatically discovers your project databases safely without executing arbitrary application code. Supported discovery targets:
Passwords are never displayed in plain text or written to logs — all previews show masked credentials ( Manual Configuration (
|
execPolicy |
Behaviour |
|---|---|
deny (default) |
EXEC / CALL are rejected like any other write. |
sandbox |
The call runs inside a transaction that is always rolled back. Every result set is returned; any INSERT/UPDATE the procedure performs is undone. Restrict which procedures qualify with execAllowlist (case-insensitive globs, optional schema. prefix). Dynamic SQL (EXEC (...), sp_executesql, xp_*) is never sandboxed. |
Sandbox mode currently supports SQL Server. Side effects that escape a transaction (mail, linked servers, consumed identity values) are not undone — keep the allowlist to read-only procedures.
Secret References
- Use
${env:VAR_NAME}to reference environment variables without committing passwords. - Use
"credentialKey": "key-name"to retrieve stored credentials from VS Code's encryptedSecretStorage.
Data Grid & Editing
- Double Click any cell to edit value inline.
- Supports strings, numbers, booleans, dates, and JSON objects.
- Changed cells are highlighted in amber.
- Press
Cmd+Sor click Save Changes to commit updates. - Press
Escapeor click Discard to revert unsaved edits. - Right-click any cell to Set NULL.
- Click the trash icon to Delete Row with primary key confirmation.
- Click Export to export loaded records to CSV, TSV, JSON, or SQL INSERT statements.
Built-in SQL Query Editor
Open via Command Palette (QueryMoat: Open Query Editor) or title bar icon:
- Syntax highlighting and auto-formatting.
- Press
Cmd+Enter(macOS) orCtrl+Enter(Windows/Linux) to run. - Click Explain to view detailed visual execution plan.
- Query History Drawer: Review recent executions, durations, and status; click to reload query.
- Export query results directly to CSV or JSON.
Model Context Protocol (MCP) Server for AI
QueryMoat embeds a local MCP server bound strictly to 127.0.0.1 so AI coding tools (Claude, Cursor, Antigravity) can inspect and query your project database:
Exposed Tools
get-database-info: Returns server engine, version, and connection status.get-tables: Lists all tables and views in the schema.get-table-schema: Full column list, data types, nullability, primary & foreign keys.get-indexes: Lists table indexes.get-foreign-keys: Lists relationship mappings between tables.get-table-rows: Paginated table rows with optional filtering.search-table: Text search within table columns.run-query: Executes SQL. Batches and procedures return every result set inresultSets; on read-only connections procedure calls run only underexecPolicy: "sandbox"(rolled back).propose-write(Pro): Proposes one change for you to approve; QueryMoat test-runs it first. See Write Approval.get-proposal(Pro): Tells the agent whether you approved, rejected, or let a proposal expire, and the result.
Connecting an AI Agent
Click the plug icon in the QueryMoat dashboard header → Copy MCP configuration and pick your client. The snippet is copied to your clipboard.
QueryMoat installs its MCP server at ~/.querymoat/mcp-server.js and keeps it up to date, so your AI client's config keeps working when the extension updates.
Claude Code (one command):
claude mcp add --transport stdio querymoat node ~/.querymoat/mcp-server.js
Cursor / VS Code (.cursor/mcp.json or .mcp.json) and Windsurf (mcp_config.json). JSON configs need the full path, which the copied snippet fills in for you:
{
"mcpServers": {
"querymoat": {
"command": "node",
"args": ["/Users/<you>/.querymoat/mcp-server.js"]
}
}
}
HTTP (any client that supports Streamable HTTP, while VS Code is open):
{ "mcpServers": { "querymoat": { "type": "http", "url": "http://127.0.0.1:42100/mcp",
"headers": { "Authorization": "Bearer <token from ~/.querymoat/mcp-token>" } } } }
The copied snippet fills in the token. Keep it out of files you commit.
How it works: the stdio server is a thin proxy. The extension writes ~/.querymoat/mcp.json (workspace path → port) when it starts; the proxy looks up the project from its working directory (--project <path> or QUERYMOAT_PROJECT override it) and forwards tool calls to the extension's HTTP server. VS Code with QueryMoat must be open for the project. projectId is injected automatically, so agents never have to supply it.
Security Controls
- Read-Only Mode: Controlled by
querymoat.mcp.readOnly(defaulttrue). OnlySELECT/WITH/EXPLAIN/SHOW/PRAGMA/DESCRIBEstatements run; keywords inside string literals and comments are ignored by the guard. Procedure calls need the connection'sexecPolicy: "sandbox"and run inside a rolled-back transaction. - Query Limits: An agent's query returns at most
querymoat.mcp.maxRowsrows (default 500; the agent is told to narrow its query) and is stopped by the database afterquerymoat.mcp.queryTimeoutSeconds(default 30; PostgreSQL, MySQL, MariaDB, SQL Server). Workspace settings can lower these but not raise them. - Prompt-Injection Defence: Rows can contain text written by anyone. Query results reach the agent wrapped in tags with a random boundary the data can't forge, with an instruction to treat everything inside as data, and a warning naming any values that read like instructions to an AI ("ignore previous instructions…").
- Agents Can't Unlock Themselves: Workspace settings can't turn read-only off. Turning it off in your user settings still needs your click in a confirmation dialog, so an agent that edits settings files can't grant itself write access.
- Project Isolation: MCP requests must target known workspace project IDs.
- Localhost Only: Binds strictly to
127.0.0.1, and refuses requests from web browsers (anyOriginheader) and DNS-rebinding attempts (anyHostother than127.0.0.1/localhost), so a website you visit cannot query your database through QueryMoat. - Access Token: Every request needs the token in
~/.querymoat/mcp-token, a file only you can read. The stdio server sends it for you; the copied HTTP configuration includes it. This shuts out callers that can reach127.0.0.1but not your files: other users on the machine, containers sharing its network, and local apps tricked into making requests. A program running as you can still read the file. QueryMoat: Reset MCP Access Token replaces it;querymoat.mcp.requireTokenturns it off, from user settings only.
Hiding Personal Data
Agents read real rows, and whatever they read ends up in prompts sent to the AI provider. QueryMoat filters everything its MCP tools return. The data grid and SQL editor still show you the real values.
Automatic masking (Pro). Personal data and secrets are detected by column name (email, phone, password_hash, api_key, card_number, ssn, date_of_birth, names, addresses) and by value (email addresses, card numbers that pass the Luhn check, JWTs, AWS/Stripe/GitHub/Slack keys, private keys), which also catches renamed columns such as SELECT email AS contact. The agent sees j***@example.com, **** 4242 or [hidden], plus a note naming the masked columns. Searching a masked column is refused, since it would reveal values one guess at a time. On by default; only user settings can turn querymoat.privacy.maskPersonalData off.
Your own rules (free). Hide or mask specific tables and columns, for every connection in settings or per connection in .querymoatrc:
{ "name": "App DB", "type": "postgres", "host": "localhost", "database": "app",
"hide": ["users.password_hash", "audit_*", "*.ssn"],
"mask": ["orders.notes"] }
Hidden tables disappear from get-tables; hidden columns disappear from rows, schemas, indexes and foreign keys; and any query or proposal that names a hidden table or column (quoted, bracketed or aliased) is refused before it runs. Rules from every settings level are combined, so a project can add rules but never remove yours.
What masking can't stop: an agent can still infer things through query shape, for example WHERE email = '...' or COUNT(*), and string functions such as substr(email, 1, 3) can reveal part of a value under a new name. Hide a column when the agent must not touch it at all.
SSH Tunnels and Cloud Sign-in (Pro)
Reach a database behind a bastion host, and sign in with your cloud identity instead of a stored password:
{ "name": "Orders (staging)", "type": "postgres",
"host": "orders.abc123.eu-north-1.rds.amazonaws.com", "port": 5432,
"database": "orders", "username": "app_reader", "environment": "staging",
"cloudAuth": "aws-rds-iam",
"ssh": { "host": "bastion.example.com", "username": "ec2-user", "privateKeyPath": "~/.ssh/id_ed25519" } }
- SSH: keys come from
privateKeyPath, your SSH agent, or~/.ssh/id_*; passwords and passphrases go in${env:VAR}. The first time, QueryMoat shows the server's host key fingerprint for you to confirm, then refuses to connect if it ever changes (sethostKeyFingerprintto pin it up front; Forget SSH Host Keys resets). The tunnel listens on 127.0.0.1 only. aws-rds-iam: uses your AWS CLI credentials (profiles, SSO, environment); setawsProfileto choose one. The region is read from the host name, or setawsRegion.azure-ad: usesaz login(or any Azure credential DefaultAzureCredential finds) for Azure SQL, Azure Database for PostgreSQL and MySQL.- Remote-host protection still applies: a database reached through a tunnel is read-only until you allow writes on it.
Write Approval (Pro)
When an agent needs to change data, it proposes the change instead of running it:
- The agent calls
propose-writewith one SQL statement and the reason for it. - QueryMoat test-runs it inside a transaction that is always rolled back and shows you how many rows would change, with a sample of them (PostgreSQL and SQLite show the rows themselves).
- You review it in the QueryMoat panel and click Approve & run (then confirm) or Reject. The agent has no tool that can approve.
- The agent calls
get-proposalto learn the outcome.
Guarantees:
- Exactly what you reviewed, once. Approval is bound to the statement's hash, runs it a single time, and proposals expire after 15 minutes.
- Never on protected databases. Read-only and production connections refuse proposals outright. Approval only runs a change where you could make it yourself in the editor.
- Nothing that could escape the test run. One statement per proposal; no
BEGIN/COMMIT/ROLLBACK, stored procedures, or dynamic SQL. MySQL and MariaDB schema changes (ALTER,DROP, ...) commit immediately, so they are shown as not test-run for you to judge from the SQL alone. - Proposals, approvals and rejections are recorded in the audit log.
Audit Log (Pro)
Every tool call an AI agent makes through QueryMoat is written to ~/.querymoat/audit/ as one JSON line: when it happened, which agent made it, the tool and SQL, whether it was allowed, blocked or sandboxed, the rule that decided it (for example environment is "production"), and where that rule is set (built-in default, user settings, workspace settings, or the connection's .querymoatrc).
{"ts":"2026-10-02T09:14:03.118Z","client":"claude-code 2.1.0","tool":"run-query","verdict":"blocked","rule":"environment is \"production\"","ruleSource":"built-in default","reason":"Query rejected: ... (contains UPDATE).","connectionName":"orders (prod)","connectionOrigin":".querymoatrc","sql":"UPDATE orders SET status = 'shipped' WHERE id = 1187","durationMs":2}
- Tamper-evident: each line carries a hash of the previous one. QueryMoat: Verify Audit Log reports any line that was changed or removed.
- Local only: files are readable only by you (
0600) and never leave your machine. Query results are not logged. - Agents can't switch it off:
querymoat.audit.enabledcan only be turned off in user settings. Old files are removed afterquerymoat.audit.retentionDays(default 90). - QueryMoat: Open Audit Log opens a viewer across all windows and days: filter by time, result, agent and database, search SQL and rules, open any entry for its details, and export what you see to CSV. Entries from a file that was edited are marked modified.
CI Check
querymoat-check lints your QueryMoat config in CI and fails the build when it finds a problem. --warn-only is opt-in, because warnings that never fail tend to be ignored.
GitHub Actions:
- uses: actions/checkout@v4
- uses: heysidhant/querymoat@v0.3.0
Any CI: npx querymoat-check [dir] [--warn-only] [--format text|github]. It exits 1 on errors, 0 when clean or with --warn-only, and 2 on bad usage.
| Rule | Level | Catches |
|---|---|---|
plaintext-password |
error | A password written into the file instead of ${env:VAR} or credentialKey |
remote-missing-environment |
error | A connection to a non-local host (or a ${env:...} host) with no environment tag |
remote-writable |
error | "isReadOnly": false on a remote host; allow writes per machine from the UI instead |
production-writable |
error | "isReadOnly": false on a connection tagged or named as production |
invalid-json |
error | A config file QueryMoat would silently ignore |
unknown-environment |
warning | A tag like prd that gets no protection |
sandbox-without-allowlist |
warning | execPolicy: "sandbox" with no execAllowlist |
workspace-disables-readonly |
warning | querymoat.mcp.readOnly: false in .vscode/settings.json (ignored by QueryMoat) |
Keybindings
| Command | macOS | Windows / Linux |
|---|---|---|
| Go to Table (QuickPick) | Cmd + K, Cmd + G |
Ctrl + K, Ctrl + G |
| Run SQL Query | Cmd + Enter |
Ctrl + Enter |
| Save Database Edits | Cmd + S |
Ctrl + S |
| Discard Cell Edit | Escape |
Escape |
Extension Settings
| Setting | Default | Description |
|---|---|---|
querymoat.debug |
false |
Enable verbose debug logging to output channel. |
querymoat.defaultPageSize |
100 |
Default row count per page (25, 50, 100, 250, 500). |
querymoat.enableAutoDiscovery |
true |
Auto-detect databases from workspace files. |
querymoat.enableCodeLens |
true |
Display CodeLens actions above models and table definitions. |
querymoat.enableMcp |
true |
Start local MCP server on 127.0.0.1. |
querymoat.mcp.readOnly |
true |
Enforce strict read-only mode for MCP queries. |
querymoat.readOnlyEnvironments |
["production", "prod", "live"] |
Environment tags that enforce read-only protection. |
querymoat.queryHistoryLimit |
100 |
Max recent queries stored in history. |
Security & Privacy Guarantee
- No Remote Telemetry: QueryMoat does not collect or transmit telemetry, user analytics, or usage statistics.
- Zero Cloud Proxies: Database traffic never leaves your local machine or local network.
- Credential Masking: Passwords and secrets are masked before ever reaching logs or UI previews.
- Content Security Policy: Webview enforces strict CSP forbidding inline scripts and remote network calls.
Support & Contributing
- 🐛 Found a bug or have a feature request? Open an issue.
- 📖 Configuration and MCP docs: github.com/heysidhant/querymoat.
- ⭐ If QueryMoat saves you time, please leave a review and star the GitHub repo.
License
QueryMoat is free to use under the QueryMoat End User License Agreement. Open-source components it includes are listed in THIRD-PARTY-NOTICES.txt.
© 2026 Sidhant Sinha