mcpField
D
db-access-mcp

db-access-mcp

本地服务
github.com/Rheopyrin数据库07 周前更新

关于 db-access-mcp

db-access-mcp 是面向 AI Agent 的数据库 MCP 服务,可通过隧道连接多种数据库,并提供查询、执行计划和文件导出。它以凭据隔离、受限只读模式及实例级连接隔离为特点。

主要功能

  1. 01支持 PostgreSQL、MySQL、Redshift 和 SQL Server
  2. 02通过 SSH 或 AWS SSM 建立隧道
  3. 03查询、执行计划与流式文件导出
  4. 04支持多种密钥提供方
  5. 05配置热加载与实例隔离

适用场景

  1. 01通过跳板机访问私有数据库
  2. 02检查 SQL 执行计划
  3. 03将大型查询结果导出为 CSV 或 JSONL
  4. 04在运行期间加载新的连接配置

MCP 相关

它通过 stdio 提供 MCP 工具,供 MCP 客户端访问配置的数据库。工具涵盖连接管理、查询、隧道管理及配置重载。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"rheopyrin-db-access": {
"command": "npx",
"args": [
"-y",
"@rheopyrin/db-access-mcp"
]
}
}
}
启动命令npx -y @rheopyrin/db-access-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@rheopyrin/db-access-mcp0.1.5

工具

11

收录的工具列表 · 更新于 2 周前

此工具无需参数。

详细介绍

db-access-mcp

npm npm downloads license: MIT node

db-access-mcp MCP server

MCP(Model Context Protocol)stdio 服务,可让 AI Agent(Claude Code、Claude Desktop 及任何 MCP 客户端)访问已配置的数据库:

  • PostgreSQL(≥ 10)
  • MySQL(≥ 5;只读会话要求 ≥ 5.6)
  • Amazon Redshift
  • Microsoft SQL Server(通过 tedious)

支持 SSH / AWS SSM 隧道、可插拔的密钥提供方(环境变量、HashiCorp Vault、AWS Secrets Manager),并采用严格的实例隔离机制——一台机器上可同时运行多个 MCP 实例,彼此不会共享连接或隧道;实例崩溃后也不会留下孤立的隧道进程。

亮点

工具: connection_list / connection_find / connection_test、query、 query_plan(EXPLAIN)、query_to_file(流式导出 CSV/JSONL,不占用模型上下文)、 up_tunnel / down_tunnel / tunnel_list、config_reload (无需重启即可加载新连接和隧道)。

安全优先设计:

  • 已验证的 SSH 隧道——根据 host_key_sha256 固定值或 known_hosts 检查堡垒主机密钥;不匹配时拒绝连接(防御中间人攻击),不会盲目信任。
  • read_only 安全保护 + 默认仅允许单条语句,同时也能阻止 SET session read-only off; INSERT … 这类绕过方式。
  • 受限的文件导出——query_to_file 只会写入导出目录或 allow_export_paths 根目录;无法覆盖 ~/.ssh、点文件或配置目录。
  • 不会泄露密钥——工具绝不会返回堆栈信息或凭据;日志会按键名脱敏,并清理内联的 user:password@host URI。
  • 可插拔的密钥提供方——环境变量、HashiCorp Vault(动态租约,支持自动刷新和原子化连接池切换)、AWS Secrets Manager、RDS IAM 身份验证令牌和临时 Redshift 凭据。

**隧道与崩溃安全:**进程内 SSH(随进程退出,不会遗留孤立端口)和由看门狗监控的 AWS SSM(即使收到 SIGKILL 也会被终止),并支持 AWS SSO 引导。每个实例的连接池和隧道彼此隔离;实例崩溃后,其隧道会在下次启动时被清理。

快速开始

// Claude Code / Claude Desktop MCP config
{
  "mcpServers": {
    "db-access-mcp": {
      "command": "npx",
      "args": ["-y", "@rheopyrin/db-access-mcp"]
    }
  }
}

首次启动时,服务会创建工作目录 ~/.db_acess_mcp (这是有意采用的拼写,属于产品约定),其中包含空的 config.json、空的 conf.d/ 目录,以及完整的 config.example.json,涵盖所有数据库类型、密钥提供方和隧道类型。导出目录(默认为 /tmp/db-access-mcp/exports)不会预先创建——首次导出时,query_to_file 会按需创建该目录。编辑 ~/.db_acess_mcp/config.json,重启 MCP 服务即可。

集成 MCP

服务通过 stdio 使用 MCP:任何能够启动 npx -y @rheopyrin/db-access-mcp(本地构建时也可使用 node <path>/dist/cli.js)的客户端都可以使用它。 每个启动的实例都完全隔离,拥有自己的连接池、隧道和空闲计时器,因此可安全地同时在多个客户端/会话中注册。

Claude Code
# current project only (writes .mcp.json in the project root)
claude mcp add db-access-mcp -- npx -y @rheopyrin/db-access-mcp

# for all your projects
claude mcp add --scope user db-access-mcp -- npx -y @rheopyrin/db-access-mcp

# with options (custom config dir, verbose logs, extra env file)
claude mcp add db-access-mcp -- npx -y @rheopyrin/db-access-mcp --workdir ~/.db_acess_mcp --log-level debug --env-file ~/.db_acess_mcp/secrets.env

在会话中使用 /mcp 检查服务状态并重新连接。服务的 stderr 日志位于 ~/Library/Caches/claude-cli-nodejs/<project-slug>/mcp-logs-db-access-mcp/ (macOS)。编辑 config.json 后,重新连接服务(/mcp)——配置只会在启动时读取。

也可以直接在项目的 .mcp.json 中声明:

{
  "mcpServers": {
    "db-access-mcp": { "command": "npx", "args": ["-y", "@rheopyrin/db-access-mcp"] }
  }
}
Claude Desktop

将相同的 mcpServers 块添加到配置文件中,然后重启应用:

  • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows:%APPDATA%\Claude\claude_desktop_config.json
Cursor / 其他 MCP 客户端

任何支持 stdio 的客户端都可以使用相同格式——命令为 npx, 参数为 ["-y", "@rheopyrin/db-access-mcp"](Cursor:~/.cursor/mcp.json,使用相同的 mcpServers 格式)。需要注意两点:

  • stdout 是协议内容——如果客户端显示 JSON-RPC 解析错误,请确保没有任何内容在命令输出中添加额外信息;所有服务日志都会写入 stderr。
  • 通过 args 传递 CLI 选项,例如: ["-y", "@rheopyrin/db-access-mcp", "--workdir", "/opt/mcp-db", "--log-level", "warn"]。
本地构建(开发)
git clone <repo> && cd db_access_mcp && npm ci && npm run build
claude mcp add db-access-mcp-dev -- node /abs/path/db_access_mcp/dist/cli.js --log-level debug
不使用客户端进行试用
npx -y @modelcontextprotocol/inspector npx -y @rheopyrin/db-access-mcp

会打开一个 Web UI,列出所有工具,并提供调用表单和实时 stderr。合理的首次会话顺序:dialect_list → connection_list → 对一个连接执行 connection_test → query。

主机要求
  • Node.js ≥ 20.19。
  • 对于 ssm 隧道:PATH 中需有 AWS CLI 和 session-manager-plugin;SSO 引导流程需要浏览器(登录会以交互方式打开)。
  • 对于 ssh 隧道:无需额外配置(使用进程内的 ssh2 客户端)。
CLI 选项
db-access-mcp [workdir] [exportdir] [--workdir <dir>] [--exportdir <dir>] [--config <file>] [--env-file <file>]... [--log-level <level>]
选项环境变量默认值
--workdir(或第一个位置参数)DB_ACCESS_MCP_WORKDIR~/.db_acess_mcp
--exportdir(或第二个位置参数)DB_ACCESS_MCP_EXPORTDIR/tmp/db-access-mcp/exports
--configDB_ACCESS_MCP_CONFIG自动发现:<workdir>/config.json + <workdir>/conf.d/*.json
--env-file(可重复指定)—无
--log-level(debug|info|warn|error|silent)DB_ACCESS_MCP_LOG_LEVELinfo

workdir 存放 config.json、conf.d/、config.example.json 以及运行时的 instances/ 和 sso/ 状态(与早期版本相同)。exportdir 是 query_to_file 写入导出文件的位置(按需创建,不会在启动时创建);allow_export_paths 可添加额外的可写根目录。

所有日志都以 JSON 行的形式写入 stderr(stdout 留给 MCP 协议使用)。键名匹配 password、token、secret、privateKey 等的值会被脱敏。

MCP 工具

工具功能说明
dialect_list列出受支持的数据库方言:名称(连接的 type 值)、默认端口,以及 query_plan 生成的计划格式。
connection_list列出已配置的连接:键、类型、描述、read_only、主机/端口/数据库、隧道名称、元数据。绝不返回凭据(基于允许列表进行清理;连接字符串仅解析主机/端口/数据库)。
connection_find按 host、port、database、type、read_only 和/或 metadata 键值对查找连接。所有筛选条件按 AND 组合。user/password 筛选条件会被忽略(并在响应中注明)。
connection_test端到端健康检查:密钥 → 隧道 → 连接池 → 单行服务器信息查询。成功时返回包含服务器版本/用户/数据库/延迟的 ok: true;失败时返回包含失败代码和提示的 ok: false(数据库无法访问是有效结果,不属于工具错误)。
query在连接上执行 SQL。接受 connection、query、可选的 database(参见多数据库连接)、max_rows 和 timeout_ms 覆盖值。结果会截断至行数上限,并设置 truncated: true。
query_to_file执行查询并将结果写入文件(根据扩展名推断为 csv/jsonl),而非写入模型上下文。file_path 相对于导出目录(默认为 /tmp/db-access-mcp/exports,按需创建),也可以是位于导出目录或已配置的 allow_export_paths 根目录下的绝对路径或 ~ 路径——不允许写入其他位置。现有文件需要设置 overwrite: true。postgres/mysql 会对行进行流式处理(默认无上限);redshift/mssql 会缓冲数据,最多处理 100k 行。
query_plan返回执行计划,但不运行查询:postgres 使用 EXPLAIN (FORMAT JSON),mysql 使用 EXPLAIN FORMAT=JSON,redshift 使用文本格式的 EXPLAIN,mssql 使用 SHOWPLAN_XML。
up_tunnel打开(或复用)连接配置的隧道,并返回 {host, port, tunnel_id, reused}。可选的 local_port 用于绑定指定本地端口;如果隧道已在其他端口打开,或指定端口已被占用,调用会失败,并在错误中返回当前端口。
down_tunnel按 tunnel_id 关闭隧道。默认情况下只会释放 up_tunnel 的固定占用;如果查询连接池仍持有该隧道,隧道会保持打开(remaining_holders);force: true 会排空持有该隧道的连接池并无条件关闭隧道。
tunnel_list列出此 MCP 实例当前打开的隧道,并进行实时健康探测:tunnel_id、隧道名称/类型、本地和远程端点、healthy、持有该隧道的连接池(connections)、up_tunnel 固定占用(pins)、外部 PID。
config_reload将配置文件重新读入运行中的服务,使在磁盘上添加或编辑的连接/隧道无需重启即可使用。绝不影响实时状态——见下文。
config_reload

编辑 config.json / conf.d/*.json(或 --config 文件),调用 config_reload, 之后的 connection_list、query、up_tunnel 等操作都会看到新的定义。 文件会重新读取、重新验证(架构 + 语义 + 方言检查),并重新应用配置中的 env_files,然后才会替换配置——无效配置不会产生任何变化:服务会继续使用先前的配置运行,工具会返回验证错误。

此重新加载有意设计为不造成中断:打开的连接池和正在运行的隧道绝不会关闭、排空、重新创建或重新配置,即使它们的定义已更改或已从文件中移除。它们会继续使用创建时的定义,直到按常规方式关闭(空闲超时、down_tunnel、服务退出);之后创建的连接池/隧道才会使用新定义。所有这类情况都会列在响应的 warnings 中。

响应包含:files(读取的文件)、connections 和 tunnels(格式为 {added, removed, changed, unchanged})、pool_defaults_changed / limits_changed / env_files_changed 标志,以及 warnings。每次调用和每个连接的 limits 都会在调用时读取,因此会立即生效;pool 设置仅适用于重新加载后创建的连接池。

query_to_file 的安全说明:写入范围仅限导出目录(默认为 /tmp/db-access-mcp/exports)以及 allow_export_paths 中列出的根目录(例如 ["/tmp", "~/data_files"])——允许写入所列根目录下的所有子路径,其他路径都会被拒绝,因此该工具无法覆盖 ~/.ssh、点文件或工作目录。它只会创建文件(不会读取或追加),并且除非明确设置 overwrite: true,否则拒绝覆盖文件。单元格内容会原样写入;在 Excel 中打开导出文件时,请注意 CSV 注入风险。

配置参考

架构是严格的——启动时会拒绝未知键,并给出易于理解的错误(用于防止拼写错误)。连接的 options 中的所有内容都会原样传递给数据库驱动程序。

{
  "vault":               { /* named Vault servers */ },
  "aws_secret_profiles": { /* named AWS Secrets Manager profiles */ },
  "env_files":           [ /* extra .env files applied at startup */ ],
  "pool":                { /* global pool defaults */ },
  "limits":              { /* global query limits */ },
  "tunnels":             { /* named tunnel definitions */ },
  "connections":         { /* named connections */ }
}
配置文件:单文件或拆分文件(conf.d)

如果未指定 --config,服务会加载 <workdir>/config.json(可选)以及 <workdir>/conf.d/*.json 中的所有文件(按名称排序、非递归、忽略点文件),并将它们合并:

  • 命名记录部分(vault、aws_secret_profiles、tunnels、connections) 会在各文件之间合并。同一名称出现在两个文件中时会导致启动错误,并指出两个文件的名称——不会静默覆盖。
  • 标量部分(pool、limits、env_files)最多只能出现在一个文件中。
  • --config <file> 只加载指定文件;不会扫描 conf.d。

所有内容都可以放在单个 config.json 中(示例展示的就是这种方式)——配置增多时,可使用 conf.d 按团队/项目拆分。

Env-ref 值

在下文注明的位置,配置值可以是内联字符串,也可以是环境变量的引用,并在需要时延迟解析:

"token": "hvs.inline"            // inline
"token": { "env": "VAULT_2_TOKEN" }  // read from the environment at use time

缺少变量只会导致实际需要它的连接失败,并会在错误中指出变量名称。

connections.<key>
字段必填描述
type是postgres | mysql | redshift | mssql
options是驱动透传选项(参见下方各数据库方言的说明)。任何字符串值都可以包含 ${provider.path} 密钥占位符。必须声明 database 和/或非空的 databases 列表(connectionString/uri 连接会将数据库包含在字符串中)。
description否由 connection_list 显示的自由文本描述。
read_only否会话级只读强制设置(参见下方语义)。默认值为 false。
metadata否供 connection_find 使用的扁平映射(值为 string/number/boolean)。
pool否此连接的连接池覆盖设置。
limits否此连接的限制覆盖设置。
tunnel否{ "target": "<tunnel name>", "localPort": 25432? }。未设置 localPort 时,将从 20000–45000 中选取一个随机可用端口。
secrets否每个连接只能使用一个提供方:{ "<provider>": <spec> }。
各数据库方言的 options
  • postgres / redshift — node-postgres 接受的任意选项: host、port、database、user、password、ssl 等;也可以使用单个 connectionString(postgres://user:pass@host:5432/db)。
  • mysql — mysql2 接受的任意选项: host、port、database、user、password 或 uri(mysql://…)。 multipleStatements 遵循下方的通用规则。
  • mssql — mssql 接受的任意选项: server(或别名 host)、port、database、user、password、 options: { encrypt, trustServerCertificate, … },或 connectionString (mssql://… URL 或 ADO 样式的 Server=…;Database=…)。
options.multipleStatements(默认关闭)

默认情况下,一次 query 调用只运行一条语句。在连接的 options 中设置 "multipleStatements": true,即可允许一次调用运行多条以 ; 分隔的语句。此限制由引擎强制执行,而非通过解析 SQL 实现:

  • mysql — 使用驱动原生的 multipleStatements 标志。
  • postgres / redshift — 关闭此选项时,查询通过扩展协议运行,因此服务器本身会拒绝第二条语句(42601);不会拆分 SQL。
  • mssql — 无法在协议层强制执行(T-SQL 批次),因此此处始终允许多条语句;请使用只读数据库用户。

关闭此选项也能防止通过 SET session-read-only off; INSERT … 绕过 read_only 连接(写入操作无法搭载在第二条语句中)。与 read_only 一样,这只是安全带;真正的保障是使用只读数据库用户。

多数据库连接(options.databases)

一台服务器通常会托管多个数据库。无需重复配置连接,只需将它们全部声明:

"shared-mysql": {
  "type": "mysql",
  "options": { "host": "...", "port": 3306,
               "databases": ["app", "reporting", "audit"],
               "user": "...", "password": "..." }
}

规则(query、query_plan、query_to_file、connection_test 可接受可选的 database 参数):

  • 未传入 database 参数 → 使用 options.database;如果连接只声明了 databases 列表,则没有隐式默认值——调用会失败,并通过 DATABASE_NOT_FOUND 列出可用名称;
  • 传入的 database 必须等于 options.database,或是 options.databases 中的成员,否则返回 DATABASE_NOT_FOUND;
  • 可以同时声明 database 和 databases;每个连接都必须至少声明其中一项(否则会出现配置错误);
  • 每个(连接,数据库)组合各自拥有一个连接池;某个连接的所有连接池共用一个隧道,该连接的最后一个连接池关闭时,隧道也会释放;
  • connection_list/connection_find 会显示 databases,而 database 查找筛选条件会匹配单个属性或列表中的任意成员;
  • databases 不能与 connectionString/uri 组合使用。
pool(全局和每连接)
字段默认值含义
max5连接池中的最大连接数。
min0保持的最小空闲连接数。
idle_timeout_ms30000连接池内驱动级别的空闲客户端超时时间。
connection_timeout_ms10000等待新连接的时间。
limits(全局、每连接、每次调用)
字段默认值含义
max_rows1000每个结果集的行数上限;超出时会截断行,并设置 truncated: true。可通过每次 query 调用覆盖。
query_timeout_ms30000查询超时时间。postgres/redshift:服务端 statement_timeout;mysql:客户端不活动超时(连接会被销毁,服务端可能仍会执行完语句);mssql:客户端 request.cancel()。可通过每次 query 调用覆盖。
idle_close_ms600000每个实例的空闲计时器:连接闲置达到此时长后,其连接池会关闭,且隧道会释放。

解析顺序:工具调用参数 → 连接的 limits → 全局 limits → 默认值。

各方言的 read_only 语义
方言机制强制执行
postgres每次签出连接时执行 SET default_transaction_read_only = on强制 — 服务端会拒绝写入(25006)。
mysql ≥ 5.6每次签出连接时执行 SET SESSION TRANSACTION READ ONLY强制。对于 5.5,该语句会失败 → 记录警告,不执行限制。
redshift尝试设置,但 Redshift 不支持尽力而为:记录警告。请使用只读数据库用户。
mssqlreadOnlyIntent 连接选项仅对 Availability Group 可读副本有效;会记录警告。请使用只读数据库用户。

如需真正可靠的保障,请始终优先使用只读数据库用户。 read_only 是一道安全带,而非安全边界。

密钥

每个连接使用一个提供方;占位符以提供方名称作为命名空间,并根据解析后的密钥对象进行解析:${env.userName}、${vault.data.password}、${aws.password}。若占位符是整个字符串,则保留原始值类型(数字仍为数字);嵌入字符串中的占位符会被替换为字符串。不匹配的命名空间会在加载配置时被拒绝。

env — 环境变量
"options": { "user": "${env.userName}", "password": "${env.password}" },
"secrets": { "env": { "userName": "PG_USER_ENV_VAR", "password": "PG_PASSWORD_ENV_VAR" } }

规范将占位符键映射到环境变量名称。缺少变量时会报错,并准确列出所有缺失项。静态 — 永不重新加载。

vault — HashiCorp Vault(多个服务端)
"vault": {
  "vault-main": { "address": "https://vault.example.com:8200", "token": "hvs...." },
  "vault-dr":   { "address": { "env": "VAULT_DR_ADDR" }, "token": { "env": "VAULT_DR_TOKEN" } }
},
...
"secrets": { "vault": { "target": "vault-dr", "path": "secret/data/databases/db4" } }
  • vault 是一个由具名服务端组成的映射;address/token/namespace 接受环境变量引用,额外的键会传递给 node-vault。
  • secrets.vault.target 用于选择服务端。未设置 target 时,会使用隐式默认客户端,该客户端仅根据 VAULT_ADDR/VAULT_TOKEN (/VAULT_NAMESPACE)构建 — 这是 node-vault 的标准变量。隐式默认客户端不属于具名映射:你命名为 "default" 的条目只是普通的具名条目。
  • KV v2 响应会被解包:占位符可直接引用密钥载荷。
  • 动态密钥(例如 database/creds/<role>)带有租约:租约会在其 TTL 的约 80% 时续期(并加入随机抖动)。续期失败时(达到最大 TTL),系统会请求新的凭据;如果凭据不同,则会原子地切换连接池(新查询会立即使用新池,正在执行的查询会在旧池上完成,然后旧池会被排空)。
  • 如果 Vault 在租约截止时间后仍不可访问,则密钥会标记为过期,并在下次使用时延迟重新解析;使用过期密钥时若认证失败,则会强制重新解析并重新连接一次。
aws — AWS Secrets Manager(命名配置文件)
"aws_secret_profiles": {
  "aws-prod": { "aws_profile": "prod", "aws_region": "us-east-1", "reload_interval_ms": 3600000 },
  "aws-dev":  { "aws_profile": { "env": "AWS_DEV_PROFILE" }, "aws_region": { "env": "AWS_DEV_REGION" } }
},
...
"secrets": {
  "aws": {
    "secret_id": "prod/erp/mssql",       // name or full ARN
    "target": "aws-prod",                 // optional: aws_secret_profiles entry
    "version_stage": "AWSCURRENT"         // optional
  }
}

aws_profile、aws_region 和 reload_interval_ms 位于命名的 aws_secret_profiles 条目中(值支持环境变量引用)。不带 target 时, 使用默认的 AWS SDK 凭证链(环境变量、共享配置、SSO、IMDS 等),且 密钥为静态值。密钥值必须是一个 JSON 对象(SecretString);其键会成为 ${aws.*} 命名空间。AWS Secrets Manager 不支持租约,因此需通过配置文件中的 reload_interval_ms(最小值为 10s)选择性启用重新加载:按此间隔重新获取密钥, 并像 Vault 一样通过原子池交换拾取轮换后的值。

env_files — 额外的 .env 文件
"env_files": ["~/.db_acess_mcp/secrets.env"]

在启动时应用,在解析任何密钥之前;--env-file <file>(可重复使用) 会将文件追加到配置列表。文件使用标准 dotenv 语法。规则(安全性):

规则原因
真实环境始终优先——进程启动时已存在的变量不会被文件覆盖。环境文件不得更改运行中环境的 VAULT_ADDR/AWS_*。
跳过 PATH、NODE_OPTIONS、NODE_EXTRA_CA_CERTS、LD_*/DYLD_*,并发出警告。防止劫持我们启动的进程(aws CLI)的二进制文件、加载器或 TLS 信任。
后续文件会覆盖较早的文件(先读取配置中的 env_files,再按顺序读取 --env-file)。确保优先级可预测。
在 POSIX 系统上,可被组或其他用户读取的环境文件会记录警告(建议使用 chmod 600)。秘密信息管理。
不会记录值;仅在 debug 级别记录键。秘密信息管理。
aws_iam — 无密码 RDS/Aurora(IAM 身份验证令牌)
"options": {
  "host": "pg.abc.us-east-1.rds.amazonaws.com", "port": 5432, "database": "appdb",
  "user": "${aws_iam.username}", "password": "${aws_iam.token}",
  "ssl": { "rejectUnauthorized": false }          // SSL is MANDATORY for IAM auth
},
"secrets": { "aws_iam": { "username": "readonly", "target": "aws-prod" } }

不会在任何地方存储密码:本地生成有效期为 15 分钟的 SigV4 身份验证令牌,并将其用作密码;标准刷新流程会在令牌过期前重新签名,并原子交换连接池。令牌始终使用 options 中的真实 RDS 主机/端口进行签名(绝不使用隧道的 127.0.0.1),因此 隧道无需任何更改即可使用;此处不支持连接字符串。配置中的可选 host/port 可覆盖端点(例如,读取器端点)。

AWS 端的先决条件:

  • 在实例/集群上启用 IAM 身份验证(IAMDatabaseAuthenticationEnabled);
  • DB 用户已绑定 IAM——postgres:GRANT rds_iam TO readonly; mysql:CREATE USER readonly IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS';
  • 调用方对 arn:aws:rds-db:<region>:<acct>:dbuser:<resource-id>/readonly 具有 rds-db:connect 权限;
  • RDS 不支持 SQL Server。每次连接都会在 CloudTrail 中留下审计记录。
aws_redshift_creds — Redshift 临时凭证
"options": { "host": "cluster....redshift.amazonaws.com", "port": 5439, "database": "dwh",
             "user": "${aws_redshift_creds.username}", "password": "${aws_redshift_creds.password}" },
"secrets": { "aws_redshift_creds": { "cluster_id": "my-cluster", "db_user": "readonly",
                                     "target": "aws-prod", "duration_seconds": 3600 } }

redshift:GetClusterCredentials 会签发一对临时用户名和密码 (有效期为 900–3600s);返回的用户名带有 IAM: 前缀,并会原样发送给 服务端。TTL 取自 API 返回的过期时间,并用于同一套自动刷新和连接池交换流程。

AWS 配置文件的 SSO 引导

aws_secret_profiles 条目可以包含与 ssm 隧道相同的 sso 块:

"aws_secret_profiles": {
  "aws-prod": { "aws_profile": "my-profile", "aws_region": "us-east-1",
                "sso": { "session": "my-sso-session", "timeout_ms": 300000 } }
}

任何引用该配置文件的 provider(aws、aws_iam、 aws_redshift_creds)使用凭证前,都会通过 aws sts get-caller-identity 验证会话;会话过期时会触发 aws sso login (浏览器),并等待解析完成,最长等待时间由 timeout_ms 指定。sso.profile 默认使用条目中的 aws_profile。登录去重依据会话名称——同一会话上的隧道和 密钥解析会共用一次浏览器登录。

添加 provider

实现 SecretProvider(src/interfaces/secret-provider.ts),并在 src/composition/modules/secrets.module.ts 中添加一行绑定代码。provider 的 name 同时是 secrets 下的配置键和占位符命名空间。

隧道

"tunnels": {
  "bastion-ssm": { "type": "ssm", "options": { "target": "i-0123...", "region": "us-east-1", "profile": "default" } },
  "bastion-ssh": { "type": "ssh", "options": { "host": "bastion", "port": 22, "username": "ec2-user", "privateKey": "~/.ssh/id_ed25519" } }
}
  • ssh — 在 MCP 进程内部运行(通过 ssh2 库):本地监听器通过 SSH 通道转发 TCP。由于它在进程内运行,即使进程收到 SIGKILL,也会随进程一起退出——不可能遗留端口。选项: host、port(22)、username、password、privateKey(文件路径,可使用 ~)、 passphrase、agent(true = 平台默认 Agent,或显式指定的 套接字/管道路径)、ready_timeout_ms。 堡垒主机密钥会经过验证(防范中间人攻击):默认根据 ~/.ssh/known_hosts 验证(明文和哈希条目,以及非标准端口的 [host]:port)。使用 host_key_sha256 显式固定密钥(ssh-keygen -lf 的指纹,可带或不带 SHA256: 前缀),将 known_hosts 指向另一个文件,或设置 strict_host_key: false 来接受任意 密钥(不安全——仅可用于选择退出验证)。未知或已更改的密钥会被拒绝。
  • ssm — 在一个精简的看门狗进程下启动 aws ssm start-session --document-name AWS-StartPortForwardingSessionToRemoteHost。 看门狗持有一条来自 MCP 进程的 stdin 管道:如果 MCP 进程因任何原因退出(包括 SIGKILL), 操作系统会关闭管道,看门狗随即终止整个 aws/session-manager-plugin 进程树(Windows 上使用 taskkill /T /F,POSIX 上使用进程组终止)。需要将 AWS CLI 和 session-manager-plugin 放在 PATH 中。选项:target(实例 ID)、region、profile、document_name。
AWS SSO 引导(ssm 隧道)
"bastion-ssm": {
  "type": "ssm",
  "options": { "target": "i-...", "region": "us-east-1", "profile": "prod" },
  "sso": { "session": "my-sso", "profile": "prod", "timeout_ms": 300000 }   // all fields optional
}

当隧道配置包含 sso 块时,会在隧道打开之前通过 aws sts get-caller-identity --profile <profile> 验证会话。 如果会话不存在或已过期,则会启动登录(浏览器流程):设置了 sso.session 时,运行 aws sso login --sso-session <name>(规范的 IAM Identity Center 形式——一个会话可以供多个配置文件使用);否则运行 aws sso login --profile <profile>。隧道会每 3 秒轮询一次,等待会话可用,直到 timeout_ms(默认为 5 分钟)超时——之后返回 TUNNEL_FAILED,并附带包含确切手动命令的提示。sso.profile 默认为隧道的 options.profile;去重/标记键为会话名称(如果存在)。

  • 此服务绝不会关闭 SSO 会话;登录进程不受看门狗监控,不会被终止,并且会在 MCP 实例结束后继续运行。
  • 并发登录会去重:同一实例内按配置文件去重;不同实例之间通过 <workdir>/sso/<profile>.login.json 标记去重——第二个实例会等待第一个实例完成登录,而不是再打开一个浏览器标签页(通过 PID 和启动时间检查忽略已退出进程的标记)。
  • 绝不会读取、解析或记录 SSO 令牌及 ~/.aws/sso/cache——只调用参数固定的 aws CLI,不使用 shell。

行为:

  • 隧道的远程端点取自连接的 options (从堡垒视角看到的 host/port)。
  • 隧道按实例缓存,并以 (tunnel name, remote host:port) 为键—— 通过同一堡垒连接到同一数据库的连接会共用一个隧道; query/up_tunnel 会复用已打开且健康的隧道。
  • 引用计数:使用隧道的最后一个连接关闭时(包括因空闲计时器而关闭),隧道也会关闭。
  • 每个实例都会将其隧道 PID 写入 <workdir>/instances/<pid>-<startTime>.json。 启动时(以及每 10 分钟),每个实例都会扫描已退出实例的文件:检查 PID 是否存活,通过操作系统进程启动时间防止 PID 被重用,并在终止任何进程前进行命令行合理性检查。
  • query 期间发生连接错误时,会检查隧道健康状况,必要时重新打开隧道、重建连接池并重试查询——最多尝试 3 次,并使用指数退避。不会重试身份验证错误。

隔离模型

每个 npx -y @rheopyrin/db-access-mcp 进程都完全隔离:各自拥有独立的配置快照、 连接池、隧道和空闲计时器。实例之间不共享任何内容;每个实例的注册表文件仅用于让后续实例在某个实例崩溃后进行清理。两个实例连接同一个数据库时,只会持有各自独立的连接池(请注意数据库的 max_connections;默认情况下,每个实例中的每个连接的连接池 max 为 5)。

错误代码

工具会返回带结构化负载的 isError: true,绝不会返回原始堆栈或凭据:

代码含义
CONFIG_INVALID配置架构或语义违规(隧道引用无效、占位符命名空间等)。
CONNECTION_NOT_FOUND未知的连接键。
DATABASE_NOT_FOUND请求的数据库未在连接中声明,或者多数据库连接调用时未提供 database 参数(提示中会列出可用名称)。
SECRET_RESOLUTION_FAILED提供方无法获取密钥(环境变量缺失、Vault/AWS 错误、路径无效)。
TUNNEL_FAILED无法打开隧道/端口被占用/CLI 缺失。
CONNECTION_FAILED重试后仍无法连接数据库,或身份验证失败。
QUERY_FAILEDSQL 错误。
QUERY_TIMEOUT查询超过了 timeout_ms。

Windows 说明

  • 路径使用 os.homedir();CLI 参数和 privateKey 中的 ~ 会手动展开。
  • 隧道进程树通过 taskkill /T /F 终止;进程检查使用 PowerShell (Windows 11 已不再提供 wmic)。
  • 同时支持 AWS CLI v2(aws.exe)和 v1(aws.cmd)。
  • 默认 SSH Agent 管道:\\.\pipe\openssh-ssh-agent。

开发

npm ci
npm run lint        # eslint (typescript-eslint, type-checked)
npm run typecheck   # tsc --noEmit
npm test            # unit tests (fast, no docker)
npm run test:integration  # requires Docker: postgres:16, mysql:8, testcontainers/sshd
npm run test:e2e    # builds, then drives dist/cli.js over real stdio MCP
npm run build       # tsup -> dist/cli.js + dist/watchdog.js

架构:使用 inversify DI 容器;每个扩展点(方言驱动、密钥提供方、隧道提供方、 MCP 工具)都是多重绑定接口,并汇总到注册表中——添加一个实现只需一个类和一行绑定。参见 src/composition/。

自动化集成测试未覆盖以下内容(已通过模拟对象进行单元测试;请手动验证): Redshift 特定功能、SSM 隧道(需要真实的 AWS)、连接真实服务器的 MSSQL、 连接真实服务的 Vault/AWS Secrets Manager。

手动验证清单

  1. 首次运行 npx -y @rheopyrin/db-access-mcp → 创建工作目录、config.json 和 config.example.json。
  2. 添加一个真实连接 → connection_list、query(SELECT 1)、query_plan。
  3. 隧道连接 → up_tunnel 返回 127.0.0.1:<port>;psql -h 127.0.0.1 -p <port> 可正常工作。
  4. 执行 kill -9 <mcp pid> → 隧道进程在几秒内消失(由看门狗监控);下次 启动时会删除过期的实例文件。
  5. Vault 动态凭据:在租约 TTL 的 80% 左右,查看日志中是否出现 secret refreshed / pool swapped after credential rotation。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。