
Dbboard
io.github.meta-taroPublished by GitHub account meta-tarov0.22.2Updated Nov 6, 2026
Hands AI agents the databases dbboard connects to: reads by default, and never a secret.
Overview
Companion MCP server for the dbboard desktop database client that lets an AI agent read the databases you already connected, without write access or secrets.
- What you can do
- Expose the connections saved in the dbboard desktop app to an agent, so it can query the same Postgres, MySQL, Turso/libSQL, D1, Firestore, MongoDB and Redis-compatible stores you use.
- Run reads inside the engine's own read-only mode, so writes fail at the server rather than behind a keyword filter.
- Keep passwords out of the agent's reach; credentials stay in the OS keychain.
- Allow writes only when switched on for a single connection, and even then refuse DROP, TRUNCATE and privilege changes.
- When to use it
- Useful when you keep databases across several providers and want an assistant to inspect or query them from one place, especially when it must be able to read production but never modify it.
- Requirements
- The dbboard desktop app for Windows or macOS, with the databases already added as connections in the app; the MCP server runs locally over stdio and shares those connections. Building from source needs Rust 1.98.0, cargo, and a C/C++ toolchain.
Installation
In SourceWeft
- Open Dbboard in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
dbboard
⬇️ Download dbboard — Windows .exe / macOS .dmg
One window for every database you look after — and a safe way to let an AI agent read them.
dbboard is a desktop database client for Windows and macOS. It speaks Postgres (and Neon, Supabase, CockroachDB, Aurora DSQL), MySQL / MariaDB, Turso / libSQL, Cloudflare D1, Cloud Firestore, MongoDB and Redis-compatible stores (Redis, Valkey, Amazon MemoryDB, Amazon ElastiCache, Upstash), keeps every password in the operating system's keychain, and ships a separate MCP server so that Claude and other agents can read the same databases without being able to change them.
When it helps
Your databases live on four different services. Production is on Neon, the side project on Supabase, the old system on a MySQL server behind a bastion, and the experiments in a Turso file. Instead of four web consoles and a terminal, they sit in one sidebar. An SSH tunnel reaches the one behind the bastion, and a colour and a tag on each connection make it obvious which one you are about to run a statement against.
You want an AI agent to read production, and it must never write.
dbboard-mcp hands your existing connections to Claude Code or Claude
Desktop. Reads run inside the database's own read-only mode (a READ ONLY
transaction, PRAGMA query_only), not behind a keyword filter, so an
UPDATE fails at the server. Writing stays off until you switch it on for
one connection, and even then DROP, TRUNCATE and privilege changes are
refused. Passwords never reach the agent.
→ MCP server
One login can see a dozen databases. Leave the database name blank when you add a Postgres or MySQL connection, and the sidebar lists every database that account can open, with its schemas and tables beneath. Click a table and the editor runs in that database; the label next to Run says which.
Someone needs one value fixed, without writing an UPDATE. Open the
table, double-click the cell, type, and Save changes. The edit is keyed on
the primary key, so a table without one stays read-only instead of guessing.
Try it
- Download the installer for your machine from the
download page
(Windows x64 / ARM64
.exe, macOS.dmg). - Open it. The builds are not code-signed, so Windows SmartScreen and macOS
Gatekeeper ask you to confirm the first time; compare the file with
SHA256SUMS.txtfrom the release first if you want to be sure. - Click Manage → Add connection, pick the database type and fill in the server. dbboard requires TLS unless you turn it off for that connection.
There are no Linux builds yet; on Linux, build from source (see Run).
A tour
Add a connection. Host, port, user and password, or paste a connection URL instead. The password goes to the OS keychain, never to a file. Leave Database blank to browse all of them.
[The add-connection form for a Postgres server on 127.0.0.1, with the database field left blank]
Find the table. Databases, then schemas, then tables. Selecting a table opens its structure: columns, types, defaults, the primary key, and the foreign keys in both directions. Notes you add stay on your machine.
[The structure view of public.orders, with its columns and three relationships]
Query it. Write SQL and press ⌘/Ctrl + Enter. Results come back in a grid you can copy as TSV or CSV or save to a file, and recent queries are kept in that connection's history.
Change a row. Select top 100 from the table's menu opens an editable grid. Edits stay pending, highlighted, until you save or discard them.
[A products table with one edited stock value waiting to be saved]
Light or dark, in your language. The theme follows the system or stays where you put it, and the interface is available in eleven languages.
[The same query in the dark theme]
Every screenshot here is taken in a separate profile against fictional data
(scripts/demo-profile), never against a
real connection (ADR-0098).
Status
Pre-1.0. Phases 1, 3, 6, and the Phase 4 AI assistant
are closed, and dbboard now doubles as an MCP server (dbboard-mcp)
for external AI agents (ADR-0046) — read-only unless you opt a connection
in, and never for privilege changes, TRUNCATE or DROP (ADR-0087).
The Turso, Cloudflare
D1, CockroachDB, Neon, Supabase, AWS Aurora DSQL, MySQL / MariaDB,
Cloud Firestore, MongoDB and Redis-compatible adapters all ship over the local HTTP backend. See
CHANGELOG.md for what
landed and docs/roadmap.md for the next phase.
The client is Tauri 2 + SvelteKit over the shared Rust core crates. The egui client it replaced shipped through v0.4.0 and was retired in ADR-0089; releases up to v0.4.0 still carry its binaries.
This is the desktop implementation. The web counterpart lives at meta-taro/dbboard-web (Nuxt + NestJS). The two share concepts and feature parity goals but are independent codebases.
Download
A prebuilt Windows installer (.exe) and macOS disk image (.dmg) for the
latest release are on the download page
(GitHub Pages), or directly on the
Releases page. Every
release ships a SHA256SUMS.txt; verify your download before running it.
The binaries are not code-signed, and will not be — a certificate is a
recurring purchase this project does not make (ADR-0106).
Windows SmartScreen / macOS Gatekeeper therefore warn on first launch, on
every release. The checksum is what you verify instead.
Goals
- Performance first — Rust core; the UI is a WebView shell over it, not a bundled browser runtime.
- Local first — no required external services to run.
- Modular — database and AI layers are decoupled.
- Extensible — new databases and AI providers can be added behind traits.
Supported Databases (initial scope)
- Turso / libSQL (SQLite-based distributed DB)
- Cloudflare D1 (SQLite-based, REST API)
- CockroachDB (distributed SQL, PostgreSQL-wire)
- Neon (managed PostgreSQL)
- Supabase (managed PostgreSQL)
- AWS Aurora DSQL (managed PostgreSQL-wire)
- MySQL / MariaDB (
mysql://…, its own SQL dialect) - Cloud Firestore (document store, REST API — read-only)
- MongoDB (document store, official driver — read-only)
- Redis-compatible stores: Redis, Valkey, Amazon MemoryDB, Amazon ElastiCache, Upstash (key-value, RESP — read-only)
All ten adapters ship today. The four pg-wire flavors share the
generic dbboard-postgres adapter (sqlx + tls-rustls-ring),
differing only in the runtime label exposed by DatabaseAdapter::id()
("postgres", "neon", "supabase", "aurora-dsql") so the
connection picker and history records can label each connection
precisely. See ADR-0018 (Neon),
ADR-0019 (Supabase), and
ADR-0021 (Aurora DSQL).
MySQL / MariaDB is the first engine on a genuinely different SQL dialect
(back-tick identifiers, back-slash string escapes, X'…' blobs, no
NaN/±Inf in DOUBLE): it has its own dbboard-mysql adapter over
sqlx's MySQL driver and a distinct SqlDialect::MySql. See
ADR-0068.
Cloud Firestore is the first adapter that is not SQL at all. A query is a
Firestore StructuredQuery
written as JSON — the same object Google's docs show, with no translation
layer and no invented query language — and nested documents come back in
Value::Json cells. It is read-only by construction: the REST API splits
reads from writes at the endpoint, and the crate contains no code able to
build a write URL. It connects with a service-account key (stored in the OS
keychain, never in connections.toml) or, with no credential at all, to the
local emulator. See ADR-0091,
ADR-0093, and ADR-0094.
MongoDB is the second, and it needed a different guarantee. A query is a
command document written as JSON — {"find": "orders", "limit": 100}, the
same object the mongosh docs show. Every MongoDB command travels one
runCommand path, so read-only cannot be structural the way Firestore's is:
it is an allowlist of commands and, per command, of their options, which
is why {"find": …, "insert": …} is refused for having an option find
does not take rather than for a remembered verb. $out and $merge are
walked for at any depth, and server-side JavaScript is refused outright.
The whole connection URI is the secret and lives in the OS keychain.
MongoDB connections cannot be tunnelled over SSH — one URI may name several
hosts and mongodb+srv:// discovers a replica set from DNS, so forwarding a
single host leaves the driver failing over to members the tunnel never
covered. See ADR-0095 and
ADR-0096.
Redis-compatible stores are the third, and the first with no tables at all.
Redis, Valkey, Amazon MemoryDB, Amazon ElastiCache and Upstash all speak
RESP, so they share one adapter and differ only in the label and the form's
defaults. A query is one command line, as redis-cli takes it —
HGETALL user:1 — and read-only is again an allowlist of commands and of
their arguments. Writes, scripts, blocking and pub/sub commands are
refused before anything is sent, and so is KEYS, which blocks the server:
SCAN gives the same answer a page at a time, and dbboard follows its cursor
until it has the keys asked for, across every node of a cluster. A command
that returns a whole hash, set, list or sorted set checks its size first. The
sidebar lists key prefixes (user:*). MemoryDB always runs in cluster mode
and over TLS. A store inside a private network is reached through an SSH
bastion: every node the cluster names is forwarded on its own, and the URL
keeps the host its TLS certificate names. See ADR-0166
and ADR-0167.
Aurora DSQL also has a second connection kind, aurora-dsql-iam
(ADR-0036): instead of a manually supplied URL
whose token expires in ~15 minutes, dbboard mints the SigV4 IAM token
itself from stored AWS credentials, for connections that need to stay
up 24/7. A background task re-mints the token and swaps in a freshly
authenticated pool before it expires
(ADR-0037, 段階B), so an unattended connection
survives Aurora DSQL's idle recycle without a manual reconnect.
The Supabase REST/auth layer is deliberately deferred to a future ADR —
at this stage all pg-wire flavors use the same postgres://… URL
contract (the aurora-dsql-iam kind excepted, which stores AWS
credentials rather than a URL).
The authoritative per-version support matrix (Tier 1 / Tier 2 / best
effort) lives in docs/compatibility.md;
versioning and DB-support policy are defined in
ADR-0011.
Architecture
Three main layers, organised as a cargo workspace:
- UI layer — a Tauri 2 shell (
apps/desktop) with a SvelteKit frontend, calling the core crates over Tauri IPC. - Database adapter layer — abstracts database-specific logic behind a single trait so multiple providers plug in.
- AI integration layer (optional) — pluggable providers (Claude, OpenAI, local LLMs). Isolated from core DB operations.
See docs/architecture.md for the full crate map
and dependency rules.
Requirements
- Rust 1.98.0. The version is pinned in
rust-toolchain.toml, sorustupinstalls it for you inside this checkout; a machine set up by hand needs the same one. It is bumped deliberately rather than tracking stable, becauseclippy -D warningsmakes the lint set part of the build (ADR-0139). cargo(bundled with Rust)- A C/C++ toolchain for
libsqlnative deps:- Windows: MSVC Build Tools
- macOS: Xcode Command Line Tools
- Linux:
build-essential
Setup
Then install the git hooks (pre-commit, commit-msg, pre-push):
They are a local convenience — CI runs the same checks on every push and pull request either way. Re-run the installer after editing a hook.
Run
The frontend never touches a database: it calls Tauri commands that wrap the
same McpService the MCP server exposes, so the engine-enforced read-only
path has one implementation. Nothing listens on a network interface. (The
loopback HTTP backend in crates/dbboard-server is the executable statement
of the contract the web sibling implements — see
docs/api-contract.md — and is no longer booted by
the client.)
By default the app opens an in-memory Turso/libSQL database, so it runs with no configuration. The backend is chosen by, in priority order:
- The environment variables documented below
(
DBBOARD_AURORA_DSQL_URL>DBBOARD_NEON_URL>DBBOARD_SUPABASE_URL>DBBOARD_PG_URL>DBBOARD_MYSQL_URL>DBBOARD_D1_*>DBBOARD_FIRESTORE_PROJECT_ID>DBBOARD_MONGODB_URI>DBBOARD_TURSO_PATH). Among the four pg-wire flavors the order is alphabetical — setting two flavored vars at once is unusual but the precedence is fully defined. DBBOARD_CONNECTION=<id>resolved againstconnections.toml— the local connection store backed by your OS keychain (ADR-0013).- If
connections.tomlhas exactly one entry, that one is auto-selected. - Otherwise an in-memory Turso/libSQL database.
See docs/connections.md for the connection-store
schema and where the file lives per OS.
Once registered, the Connections window (top bar) lets you add / edit / delete entries and swap the active connection on the running process — the per-row Connect button swaps the backend in-place, no app restart needed (in-flight requests intentionally finish on the old backend; new ones pick up the new one). See ADR-0020 for the swap semantics.
The same window can Export all connections to a passphrase-encrypted
.dbbx bundle (age scrypt + ChaCha20-Poly1305) that carries the
connection metadata and its secrets, and Import one on another
machine — the one-file way to move a whole setup without hand-seeding the
keychain. Import is skip-and-report on id/reference conflicts. See
ADR-0038 and
docs/connections.md.
A connection to a database that only listens on a bastion's localhost
can reach it through an SSH tunnel: the desktop connection form has an
SSH tunnel section (for the Postgres family, MySQL and the Redis-compatible
stores) to set the
bastion host/port/user, key- or password-based auth, and a mandatory
server host-key pin (fingerprint or known_hosts). dbboard opens a
pure-Rust local port forward (russh) and rewrites the connection URL to the
tunnel before dialing; the key passphrase / SSH password live only in the
keychain. See ADR-0069 and
docs/connections.md.
The top bar carries a Language / 言語 menu listing
the 11 shipped locales by their native names. Picking one swaps the
UI language in place; the DBBOARD_LANG env var still drives the
startup default and is unchanged by the runtime switcher. See
ADR-0022.
The Help menu shows the running version and, when a newer release has
been published, an Update available notice with the release notes. This is
the one network call dbboard makes on its own behalf: a single best-effort
check at startup against the signed latest.json published with each release,
compared to the running version. You choose whether to install it; the
download is verified against the release signing key before anything is
replaced (ADR-0067). The check is silent when offline or
on any error, and you can turn it off completely by setting
DBBOARD_NO_UPDATE_CHECK to any non-empty value. See
ADR-0040.
A Backup… button on the query toolbar dumps the active connection to a
single self-contained .sql file — schema plus data, in the source engine's
own dialect (verbatim DDL for the Turso/D1 SQLite family, reconstructed DDL
for the Postgres family including Neon, Supabase, and Aurora DSQL). The dump
streams INSERT batches straight to disk with keyset pagination, so a large
database never buffers in memory. Before starting, a preflight row count warns
if the database is bigger than a threshold (500k rows by default, adjustable
under the Backup menu and remembered across restarts) so a giant dump
isn't kicked off blindly; while running, a window shows table/row progress and
a percentage bar and can Cancel at any time (the file keeps the partial
dump). See ADR-0049 and ADR-0050 (the
configurable threshold).
A Restore… button on the same toolbar plays a .sql file back into the
active connection — the read side of the backup above, and it also accepts
foreign scripts (pg_dump, sqlite3 .dump). It runs whole-script against an
engine of the matching family (SQLite for Turso/D1, Postgres for Neon,
Supabase, and Aurora DSQL) and applies statements inside a transaction where
the engine supports one (Aurora DSQL falls back to per-statement). To stay
safe, restore targets empty databases: loading into a connection that
already holds tables raises a confirmation rather than merging or diffing.
A window shows per-statement progress and can Cancel mid-run; the summary
reports how many schema and data statements applied and which failed. See
ADR-0051.
The examples below set an env var for one run; they assume the working
directory is apps/desktop (that is where pnpm tauri dev lives). Anything
you would rather keep is better placed in connections.toml — see
docs/connections.md.
Local Turso/libSQL (default)
Cloudflare D1
Set all three of the following to connect to D1 instead of Turso:
The account and database IDs are shown in the Cloudflare dashboard
(Workers & Pages → D1) or via wrangler d1 info <database-name>. Create
the API token under My Profile → API Tokens with a D1 read/write
permission. If any of the three required variables is missing, the app
falls back to the local Turso default.
Cloud Firestore
The project id alone is enough to select Firestore. Everything else is optional, which makes the emulator the zero-configuration case:
A service-account key is never sent over plain HTTP: an http:// base URL
is refused outright when one is configured, and the client is built
https_only so a redirect cannot route around it. The emulator is exempt
because it issues no credential to leak.
Queries are Firestore StructuredQuery objects in JSON, not SQL — the
sidebar's Select top 100 generates one for you:
MongoDB
DBBOARD_SSH_* is refused on a MongoDB backend rather than ignored: a URI
may list several hosts and mongodb+srv:// discovers a replica set from
DNS, so a single-host forward would appear to work and then fail over to a
member the tunnel does not front.
Queries are command documents in JSON, not SQL — the sidebar's Select top 100 generates one for you:
Reads are the allowlist aggregate, count, distinct, find,
listCollections and listIndexes; anything else, including a read
carrying $out, $merge, $where, $function or $accumulator, is
refused before it reaches the server.
CockroachDB / PostgreSQL
Set a single connection string to connect to CockroachDB or any generic
PostgreSQL-wire database (vanilla Postgres, self-hosted) via the
dbboard-postgres adapter:
For CockroachDB Cloud, copy the connection string from the cluster's
Connect dialog in the CockroachDB Cloud Console (Basic free tier
works). For a self-hosted node started with
cockroach start-single-node, use its postgresql://… string; the
default SQL port is 26257. CockroachDB requires TLS, so keep
sslmode=verify-full (or the mode your deployment expects).
For Neon, Supabase, and AWS Aurora DSQL the same adapter is
used but the connection is labelled distinctly at runtime
("neon", "supabase", "aurora-dsql" vs "postgres") so the
picker and history records can tell them apart. Each flavor has its
own env var, all of which outrank DBBOARD_PG_URL:
All four pg-wire vars contain credentials — keep them out of version
control (use .env, which is gitignored). The app never logs them.
Because the Aurora DSQL IAM token expires in ~15 minutes, the env-var
form above suits short sessions. For a long-lived / 24/7 connection use
the aurora-dsql-iam connection kind instead, which stores AWS
credentials in connections.toml + the OS keychain and lets dbboard
mint the token itself. It is configured in the connection store, not via
an env var — see docs/connections.md and
ADR-0036.
AI integration (optional)
dbboard ships an optional AI panel that can explain SQL and suggest queries against the active connection's schema. The panel and the menu entry that toggles it are both hidden when no provider is configured — graceful degradation = absence (see ADR-0023 Decision 11).
When wired, the AI Assistant menu entry (top bar, between
Connections and Language) opens a two-mode window: Explain SQL
(paste SQL, get a natural-language walkthrough) and Suggest SQL
(describe a question, get a SQL draft using the active connection's
table list as context). Responses render inline; errors are surfaced
with translated prefixes so a 429 or network failure does not look
identical to a successful empty response. AI calls do not travel
the dbboard-web HTTP contract — they go directly from the desktop
binary's worker thread to the provider over reqwest.
Responses stream incrementally for providers that advertise the capability (both wired providers do — the Anthropic provider per ADR-0026, the OpenAI provider per ADR-0052). Text appears chunk by chunk as the model generates it, and a running Tokens: N in / M out meter updates from the cumulative usage chunks. While a request is in flight the Send button is replaced with Cancel: clicking it drops the in-flight stream (closing the HTTP connection so the server stops generating) while preserving any partial text already shown, and a quiet Cancelled. line marks the outcome. The same cancel button works on the atomic path used by providers without streaming support.
In Suggest mode, an Include column details checkbox appears when the active database adapter can describe tables (all three bundled adapters can — ADR-0028). Ticking it makes Send first fetch each table's columns and primary key from the live connection, then embed that schema in the prompt, which largely eliminates hallucinated column names in the drafts. The trade-off is prompt size: the full schema counts against the provider's context window and your token bill — watch the token meter, and leave the box off (its default, reset each session) for large schemas or metered keys. If some tables fail to describe, a warning shows the count and the suggestion proceeds with the rest.
Two providers are wired today — the Anthropic Messages API and
the OpenAI Chat Completions API (ADR-0052, default model
gpt-4o). Both are configured via either of two paths, evaluated
in the order below; the first to resolve wins.
1. ai-providers.toml + OS keychain (recommended)
Add one or more entries to a per-user ai-providers.toml next to
connections.toml (path: same OS config dir as the connection store)
and the API key is held in the OS keychain — Windows Credential
Manager, macOS Keychain, or Linux Secret Service — under
dbboard.ai.<id>.api_key. The TOML file itself records the keyring
reference, never the literal key.
The runtime store is the same one the Settings UI mutates (open it
from the AI Providers menu, ADR-0025 slice b): adding an entry
seeds the keychain, "Use" rebuilds the in-process provider and
updates active_id atomically, and "Delete" tears down the entry
and its secret together. A hand-edited TOML works too — useful for
seeding a new machine without opening the window — provided the
keyring_api_key_ref it names has a matching keychain entry:
The kind discriminator sits inline on each [[providers]] entry
("anthropic" or "openai"); model is optional and falls back to
the provider's default when omitted:
The env-variable path below stays Anthropic-only; configure OpenAI
through ai-providers.toml (or the AI Providers Settings window).
2. Environment variables (back-compat / CI)
When DBBOARD_ANTHROPIC_API_KEY is set, it always wins over
ai-providers.toml. This preserves the original Stage 1 wiring for
headless / CI use and avoids surprising a user who already exports
the env var. Unset it to let the TOML path take over:
If neither path resolves a provider (or any branch fails — missing
keyring entry, construction error), the binary logs to stderr and
continues without AI; the panel and menu entry are hidden. The key
never appears in Debug output or in history.jsonl; it is held
only in memory for the process lifetime.
Every completed AI call (streamed or atomic, ok / error /
cancelled) is recorded to history.jsonl as a kind: "ai" record
alongside SQL history (schema v:2 per ADR-0027). The prompt and
response are written verbatim — same stance as the SQL text in
v:1 query records. The at-rest protection is the same too: 0o600
on Unix / user-only DACL on Windows, per ADR-0024. On a shared
machine, be aware that anything typed into the AI panel — including
schema-context in follow-ups and any secrets pasted into an
Explain request — lands unredacted on disk under your user account.
Remaining deferred Stage 2 capability (full-DDL schema snapshots + function-calling — Group D) is tracked in ADR-0023 §9. Groups A / B / C are closed (ADR-0025 / ADR-0026 / ADR-0027).
MCP server
Besides being an AI client, dbboard also ships as a headless
MCP server — dbboard-mcp — that
hands the databases dbboard is already configured with to an external AI
agent (Claude Desktop, Claude Code) as a small tool surface over stdio.
It reuses the exact same connections.toml + OS keychain machinery as
the GUI, so it adds no new place to keep credentials. See
ADR-0046 and the crate README,
crates/dbboard-mcp/README.md, for the
full spec.
Twenty-two fixed tools. Seven read a database — list_connections,
list_tables, describe_table, search_schema (ADR-0053),
list_relationships (ADR-0054), run_read_query, and get_annotations
(dbboard's local notes, ADR-0045) — plus run_write and dump_database
(ADR-0087). Seven reach no database at all, and work the window instead:
get_ui_locale / set_ui_locale change the app's display language
(ADR-0107), capture_window returns a PNG of the running window
(ADR-0108), and set_editor_sql / run_query / open_ai_panel /
open_ai_settings drive it (ADR-0109) — so a claim about what the
interface renders can be set up, performed and checked instead of
asserted. Those seven act on a screen someone is sitting in front of; all
but the two getters fail outright when dbboard is not running. Two
reach nothing whatever. get_server_info names the build that is
answering (ADR-0116), because this binary is installed by hand and a
stale one is otherwise indistinguishable from a broken one; about
describes the product itself — what it is for, which engines it speaks,
and what each released version changed, with the changelog compiled into
the build so the answer describes the binary that is replying
(ADR-0154).
The last four work on the connection list itself, and none of them opens a
database. add_connection registers a connection in connections.toml so a
database an agent has just set up is usable without asking a person to
retype its path — and only for the kinds that store nothing in the keychain,
a local SQLite/libSQL file and the Firestore emulator (ADR-0134). Everything
that needs a password, a token or a key is refused in the tool's own
description, before the credential is sent rather than after.
set_connection_mark and move_connection colour and reorder the list
(ADR-0136), which is the wrong shape of work for a person doing it twenty
times and the right shape for an agent doing it once. export_connections
seals connections into an encrypted bundle for another machine, mints the
passphrase itself and files it in this machine's keychain rather than
returning it, and is refused entirely until a human has named a directory
for the files in connections.toml (ADR-0140).
The security posture is the reason it is safe to point an agent at:
- Secrets never cross the wire. The only connection metadata
serialized is
{ id, name, kind }— no URLs, tokens, or keyring references, and no error message embeds one. - Reading is engine-enforced read-only, not string-matched.
Postgres-wire runs each statement inside
BEGIN TRANSACTION READ ONLY, libSQL/Turso underPRAGMA query_only, and D1 classifies the AST — soUPDATE, DDL, multi-statement batches, andSELECT … FOR UPDATEall fail at the source. - Writing is off until a human turns it on, per connection
(
mcp_writeinconnections.toml, or Connections → Edit → AI agent access). Even thenrun_writeonly accepts an allowlisted statement (INSERT/UPDATE/DELETE/MERGE,CREATE TABLE/VIEW/INDEX/SCHEMA,ALTER TABLE) — classified on the AST, failing closed — andGRANT/REVOKE/DENY, user and role DDL,SET PASSWORD,TRUNCATE, andDROPof anything at all are refused whatever the flag says (ADR-0087). - Exporting is off until a human names a directory for it
(
[mcp_export]inconnections.toml), and the passphrase for what it seals is generated by dbboard, filed in this machine's keychain, and never returned — a tool result is plaintext in an agent's transcript, so the bundle and its key must not travel together (ADR-0140). - Result sets are bounded.
run_read_queryclampsmax_rowsto a hard cap of 1000 (default 200) with atruncatedflag. - stdout is sacred. JSON-RPC frames own stdout; all logging goes to
stderr (
RUST_LOG, defaultinfo).
Get it from the
latest release —
dbboard-mcp-windows-x86_64.exe, dbboard-mcp-windows-aarch64.exe (Windows
on ARM) or dbboard-mcp-macos-universal. It is a
single executable with no runtime dependencies.
On Windows, from v0.22.2 the desktop installer brings it along and puts it
at %LOCALAPPDATA%\dbboard\dbboard-mcp.exe, so if dbboard is installed you
can skip straight to registering it, and every upgrade replaces the server
with the app (ADR-0169). Without the app, or on macOS, download it and put it
somewhere stable, because the path goes into the agent's config:
Register it with Claude Code in one command — --scope user makes it
available in every project on the machine:
To build it yourself instead:
Or with Claude Desktop, by adding the absolute path to the built
binary in claude_desktop_config.json
(%APPDATA%\Claude\claude_desktop_config.json on Windows,
~/Library/Application Support/Claude/claude_desktop_config.json on
macOS):
Either way, restart the agent afterwards. Each client spawns its own
dbboard-mcp process and holds it for the session, so an already-running
agent keeps talking to the old one — and restarting the dbboard desktop
app does nothing to it, because they are separate processes.
With no arguments it reads the same per-user connections.toml the GUI
uses; pass --config (or set DBBOARD_CONFIG) to point at a curated,
least-privilege subset instead. That is the only thing the environment
decides: a tool call names a connection_id, and the server resolves it
against the store file and the keychain, so a connection the store does
not describe cannot be reached. Full configuration — the per-OS config
paths, running several agents at once, TLS behind a corporate proxy, and
the literal error strings a failed connection produces — is documented in
crates/dbboard-mcp/README.md.
To point an agent working in a different repository at dbboard, copy
the block in
docs/agent-onboarding.md into that
repository's CLAUDE.md / AGENTS.md. An agent does not go looking for
tools it has not been told about — one that searched the web for dbboard
concluded it was "not a publicly available tool".
A walkthrough in Japanese, from downloading the binary to the first
refused DROP, is on Zenn:
Claude Code に自分の DB を触らせる.
Development
Before committing, the pre-commit hook runs:
Before pushing, the pre-push hook also runs:
Pure deletion pushes (git push --delete <branch>) skip the
build/test cycle — there is no working tree to validate.
You can run these manually at any time.
Security checks
dbboard creates connections.toml and history.jsonl under your
per-user config dir (DBBOARD_CONFIG_DIR=<path> replaces it — every
file dbboard owns moves together, which is how you start it with an
empty profile for a demo or a screenshot; see
docs/connections.md).
On Unix both land as mode 0o600; on Windows
they inherit the user-only DACL of %APPDATA%\Roaming\<user>\. If
the resolved config dir lives under a cloud-sync vendor folder
(OneDrive Known Folder Move, iCloud Drive, Dropbox, Google Drive),
the binary emits one stderr warning at startup naming the vendor.
The single most effective hardening on a lost laptop is full-disk
encryption — enable BitLocker / FileVault / dm-crypt. See
docs/connections.md § File permissions
and ADR-0024 for the full posture.
cargo-deny gates the dependency graph on advisories, licenses,
duplicate versions, and unknown sources. Configuration lives in
deny.toml.
CI does not run this yet; run it locally when adding or upgrading a
dependency. New license expressions surfaced by the check go into
deny.toml's licenses.allow list with a one-line rationale.
Packaging & distribution
Windows and macOS bundles are produced by the Tauri CLI from
apps/desktop. Linux is not built today.
Note on trust. The artifacts are not code-signed, and that is a decision, not a gap waiting to be filled (ADR-0106): Windows SmartScreen and macOS Gatekeeper will warn about an unknown publisher on every release. Verify a download against the published
SHA256SUMS.txt(see Release builds & checksums) — that, not the OS warning, is what tells you the file is the one this repo built. This is separate from the updater signing key, which is already in use and is what proves an auto-update came from this project (ADR-0067).
Building a bundle locally
The bundles land under target/release/bundle/ — the workspace shares one
target directory, so they are at the repository root and not beside the crate
that produced them. They are named after productName, which is dbboard;
the cargo package is still dbboard-desktop, and releases v0.5.0 through
v0.14.0 carry that spelling in their filenames:
App identity — bundle identifier, icons, window defaults, updater endpoint —
lives in apps/desktop/src-tauri/tauri.conf.json;
the icons are generated from assets/ (see DESIGN.md).
Because the frontend is a static SPA, pnpm tauri build runs the Vite build
first; a stale apps/desktop/build/ is never what ships.
Release builds & checksums
Pushing a v*.*.* tag runs .github/workflows/release.yml,
which builds the Windows and macOS bundles on their native runners and attaches
them to the matching GitHub Release together with a combined SHA256SUMS.txt
and the signed latest.json the in-app updater reads. A manual
workflow_dispatch run builds the same artifacts as a smoke test without
publishing. The download page then
serves whatever the newest release holds — it reads the Releases API at load,
so it needs no separate deploy. Verify a download:
Handing a build to someone
Three role-specific guides cover the actual handoff:
- Producing a build (maintainer): build the installer, optionally export an
encrypted connection bundle, deliver, and keep artifacts out of the
public repo —
docs/maintainer/internal-distribution.md. - Trying it as a tester: install, run, and report feedback —
docs/internal-testing.md. - Standing up the three fixed data-collection connections (operator):
docs/collector-setup/README.md.
Connections and their secrets move between machines as a single
passphrase-encrypted .dbbx bundle (Export / Import in the connection
window, ADR-0038); the passphrase always travels on a
separate channel.
Contributing
This project follows the rules in CLAUDE.md. In short:
- Write a failing test before changing behaviour.
- Keep changes small and focused.
- Use conventional-style commit messages in English.
- Record non-trivial decisions in
docs/decisions.md.
License
See LICENSE.
Source: README.md at commit b501e62
Tools
0Version history
3- v0.22.2LatestNov 6, 2026
- v0.22.1Nov 5, 2026
- v0.22.0Nov 4, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts