PluginWorld
Db

dblink

MCP

Enables agents to connect to and work with PostgreSQL, MySQL, Redis, SQLite, and MongoDB through a uniform tool surface for opening connections, running queries and commands, inspecting schemas, and managing documents.

@fb0sh · v2.0.1 · MIT License · updated today

SECURITY

B

SCORE

68

STARS

▲ 0

PLUG IN

git clone https://github.com/fb0sh/dblink.git

See the README to configure this MCP server

README

dblink

A Model Context Protocol (MCP) server that lets an agent talk to multiple databases through a small, uniform tool surface: PostgreSQL, MySQL, Redis, SQLite and MongoDB.

open_connection(dsn) ──▶ connection_id ──▶ db_query / db_execute / db_list_tables / db_describe_table / redis_command / mongo_find / mongo_aggregate / mongo_write / mongo_list_collections / mongo_describe_collection ──▶ close_connection

Install & run

# stdio (default, no auth — for local use)
npx @fb0sh/dblink

# HTTP (requires a bearer token; refuses to start without one)
DBLINK_HTTP_TOKEN=change-me npx @fb0sh/dblink --http 7331

CLI

dblink                                              # stdio server (default)
dblink serve --host 0.0.0.0 --port 7331 --token xxx  # HTTP server
dblink client --url http://127.0.0.1:7331/mcp --token xxx   # interactive REPL
dblink client --list                                # list tools
dblink client --tool db_query --args '{"connection_id":"conn_x","sql":"select 1"}'

dblink serve requires a token (--token or DBLINK_HTTP_TOKEN) and refuses to start without one. dblink client is a thin MCP client for manual testing and scripts.

MCP client config (stdio) example:

{
  "mcpServers": {
    "dblink": { "command": "npx", "args": ["-y", "@fb0sh/dblink"] }
  }
}

Library usage (integration)

Hold one MCP session instead of reconnecting per call:

import { createDblinkClient } from "@fb0sh/dblink/client";

const dblink = await createDblinkClient({
  url: "http://127.0.0.1:7331/mcp",
  token: process.env.DBLINK_HTTP_TOKEN,
});
const tools = await dblink.listTools();
const opened = await dblink.call("open_connection", { dsn: "sqlite::memory:" });
const rows = await dblink.call("db_query", {
  connection_id: opened.json.connection_id,
  sql: "select 1 as v",
});
await dblink.close();

createDblinkClient keeps the session alive (one initialize handshake). Use callOnce(...) for fire-and-forget scripts.

Tools

Tool Purpose
open_connection(dsn, read_only=true, name?) Open/reuse a connection, return connection_id
close_connection(connection_id) Close and release
list_connections() Alive/dead status of active connections
db_query(connection_id, sql, params?, limit?) Read-only SQL
db_execute(connection_id, sql, params?) Write SQL (needs read_only:false)
db_list_tables(connection_id, schema?) List tables/views
db_describe_table(connection_id, table, schema?) Columns + indexes
redis_command(connection_id, command, args?) Read-only Redis commands (allow-list)
mongo_find(connection_id, collection, filter?, projection?, sort?, limit?, database?) Query documents (relaxed EJSON)
mongo_aggregate(connection_id, collection, pipeline, limit?, database?) Aggregation pipeline (no $out/$merge when read-only)
mongo_write(connection_id, collection, action, payload, database?) insert/update/delete (writable connections only)
mongo_list_collections(connection_id, database?) List collections
mongo_describe_collection(connection_id, collection, database?) Sample document, indexes, inferred fields

Supported DSN schemes: postgres://, postgresql://, mysql://, redis://, rediss://, mongodb://, mongodb+srv://, sqlite: (file or :memory:).

Configuration (environment)

Variable Default Meaning
DBLINK_HTTP_TOKEN — Required when --http is used; bearer token
DBLINK_BIND 127.0.0.1 Bind address; 0.0.0.0 must be explicit
DBLINK_PORT 7331 HTTP port (or pass --http <port>)
DBLINK_POOL_SIZE 5 Max clients per pool
DBLINK_IDLE_MS 900000 Idle pool eviction (15 min)
DBLINK_MAX_POOLS 20 Max distinct connection pools per process

Limits: 100 rows by default (max 1000), 256 KB per result, 30 s statement timeout. Truncated results return truncated: true.

Errors are uniform: { ok: false, error: { code, message, hint? } } with code ∈ CONN_NOT_FOUND | CONN_CLOSED | READ_ONLY_VIOLATION | SQL_ERROR | TIMEOUT | LIMIT_EXCEEDED | UNSUPPORTED.

Security — read this

  • read_only is not a security boundary. The real boundary is the database account. Use a read-only database user for read-only connections. The built-in SQL guard (single statement, no DDL/DML, no SELECT ... INTO) is best-effort and can be bypassed (CTEs, functions, comments, etc.). See docs/adr/0003-read-only-boundary.md.
  • DSNs are passed by the agent and transit the model context; the server itself never writes plaintext credentials to its logs.
  • HTTP is fail-closed: without DBLINK_HTTP_TOKEN the server refuses to start. Default bind is 127.0.0.1; exposing it on 0.0.0.0 is your call and requires the token to be protected.
  • stdio transport is unauthenticated by design (local, single user).

Development

npm install
npm run build      # tsc -> dist/
npm test           # unit tests (SQLite + fakes); docker tests skipped
docker compose up -d   # postgres/mysql/redis for integration
DBLINK_TEST_PG_DSN=postgres://dblink:dblink@127.0.0.1:55432/dblink \
DBLINK_TEST_MYSQL_DSN=mysql://dblink:dblink@127.0.0.1:53306/dblink \
DBLINK_TEST_REDIS_DSN=redis://127.0.0.1:56379 \
DBLINK_TEST_MONGO_DSN=mongodb://127.0.0.1:57017/dblink \
npm run test:integration

See docs/adr/ for design decisions, GLOSSARY.md for vocabulary, and .scratch/dblink/ for the spec and tickets.

SIMILAR PLUGINS