sql-mcp 是一个面向 SQL Server 与 PostgreSQL 的只读 MCP 服务器,让 Claude Code 等 MCP 客户端能够查看数据库、模式、表、视图、索引、外键、函数和存储过程元数据,并执行受限制的 SELECT 查询。它适合让编程 Agent 辅助理解遗留数据库、生成文档和排查查询问题,但“只读”必须同时由应用层和数据库权限层保证。
最重要的原则是:SQL 文本过滤只能作为第一道防线,专用只读数据库账户才是最终保障。即使 MCP 服务的校验代码出现缺陷、依赖行为变化或未来新增工具,只要数据库登录本身没有写权限,攻击者和提示注入也不能轻易把查询升级成数据修改。
项目当前支持 SQL Server 和 PostgreSQL,要求 Node.js 22 或更高版本;PostgreSQL 目标版本为 13 以上。SQL Server 可以是本地实例、Azure SQL 或容器实例。部署前应创建专门的只读账户,不能复用应用程序账户、数据库所有者或系统管理员。
第一层位于 MCP 应用。execute_query 会去除 SQL 注释,要求语句以 SELECT 或 WITH 开头,并拦截 INSERT、UPDATE、DELETE、DROP、CREATE、ALTER、TRUNCATE、EXEC、MERGE、GRANT 等写入或高权限关键词。模式浏览工具则使用参数化查询访问系统视图。
这种校验可以在请求抵达数据库前拒绝明显危险语句,也能为用户返回清晰错误。但字符串和语法检查不能证明任意 SQL 永远无副作用。数据库方言、函数、扩展、链接服务器、未来特性和解析差异都可能扩大攻击面。
第二层位于数据库授权。SQL Server 应让专用登录只属于目标数据库的 db_datareader,并按需增加 VIEW DEFINITION;PostgreSQL 应使用只具备 CONNECT、USAGE 和 SELECT 的专用角色,并撤销默认写权限。数据库引擎会在真正执行时再次阻止未授权操作。
应用层过滤提供易用性和早期阻断,数据库层权限提供不可绕过的底线。生产环境还应叠加网络限制、模式白名单、表黑名单、敏感列遮罩、行数上限和审计日志,形成多层控制。
先确认 Node.js 版本满足要求,再从项目仓库检出代码、安装依赖并构建:
node --version
git clone <official-repository>
cd sql-mcp
npm install
npm run build
生产部署应固定提交或发布版本,审查 package-lock.json,并在隔离环境完成依赖扫描与测试。不要直接在数据库服务器上使用浮动分支构建,也不要让 MCP 进程拥有不必要的操作系统权限。
复制示例环境文件后填写连接参数:
cp .env.example .env
.env 包含数据库凭据,必须排除在 Git、镜像层、日志和支持包之外。文件权限只允许运行 MCP 的服务账户读取。更成熟的部署可从秘密管理系统在启动时注入凭据。
通过 DB_PROVIDER 选择驱动。mssql 是默认值,PostgreSQL 使用 postgres:
DB_PROVIDER=mssql
DB_PROVIDER=postgres
一个进程只使用当前配置的提供器。需要同时连接不同类型或不同安全域的数据库时,应启动多个独立实例,分别使用不同账户、环境文件和 MCP 名称,避免把开发、测试与生产凭据混在同一进程。
SQL Server 可以使用完整连接字符串,也可以分别配置主机、端口、数据库、用户名和密码。设置 SQL_CONNECTION_STRING 后,单独的 SQL 参数会被忽略。连接字符串示例中的口令必须替换,不能照抄占位值。
DB_PROVIDER=mssql
SQL_SERVER=db.example.internal
SQL_PORT=1433
SQL_DATABASE=Reporting
SQL_USER=sql_mcp_reader
SQL_PASSWORD=replace-with-secret
SQL_ENCRYPT=true
SQL_TRUST_SERVER_CERTIFICATE=false
SQL_REQUEST_TIMEOUT=30000
生产连接应启用加密并验证服务器证书。TrustServerCertificate 适合本地自签名测试,不应作为解决证书错误的永久开关。超时限制可以防止 Agent 发出的昂贵查询无限占用连接,但仍需在数据库侧配置资源治理。
项目能规范化部分 .NET 风格连接键,例如 Data Source、Initial Catalog 和 User ID,也会移除底层驱动不支持的键。迁移现有连接字符串时仍应逐项检查,不要假定所有应用配置都能原样复用。
由数据库管理员创建独立登录,并在每个允许暴露的数据库中映射用户:
CREATE LOGIN sql_mcp_reader
WITH PASSWORD = 'replace-with-strong-secret';
USE [Reporting];
CREATE USER sql_mcp_reader FOR LOGIN sql_mcp_reader;
ALTER ROLE db_datareader ADD MEMBER sql_mcp_reader;
db_datareader 允许读取该数据库中的用户表和视图,不应再加入 db_datawriter、db_owner 或服务器管理员角色。若只需要部分模式,最好不用宽泛固定角色,而是创建自定义角色,对允许对象显式 GRANT SELECT。
需要读取视图、函数、触发器或存储过程定义时,可以增加数据库级 VIEW DEFINITION:
GRANT VIEW DEFINITION TO sql_mcp_reader;
定义本身可能包含内部表名、业务规则、注释甚至错误嵌入的秘密。只有确实需要代码理解时才授权;敏感数据库可以对单个对象授权,而不是授予整个数据库定义可见性。
查看 SQL Agent 作业与历史需要 msdb 中的 SQLAgentUserRole 或更高权限;查看链接服务器需要 VIEW ANY DEFINITION 或 sysadmin。后者范围很大,不应仅为方便 Agent 探索而授予。
如果业务不需要作业历史和链接服务器,就让相关工具返回权限错误。缺少某个元数据功能比扩大生产账户权限更安全。确需使用时,创建单独实例和账户,并对返回结果做遮罩与审计。
不要为了让所有工具都“显示绿色”而加入 sysadmin。MCP 客户端能够被自然语言驱动,来自数据库内容、工单或文档的提示注入都可能诱导它调用更高权限工具。
PostgreSQL 可使用连接字符串或独立参数:
DB_PROVIDER=postgres
PG_HOST=pg.example.internal
PG_PORT=5432
PG_DATABASE=reporting
PG_USER=sql_mcp_reader
PG_PASSWORD=replace-with-secret
PG_SSL=true
PG_STATEMENT_TIMEOUT=30000
生产环境启用 TLS,并正确验证服务端证书。statement timeout 限制单条语句时间,配合连接池上限和只读事务设置,可降低复杂查询拖慢数据库的风险。
Azure Database for PostgreSQL 还可以选择 Microsoft Entra 身份验证。该模式通过 Azure CLI 凭据按需获取短期令牌,不保存固定 PG_PASSWORD,并会强制 SSL。运行服务的身份必须已经登录且映射为 PostgreSQL 角色。
PostgreSQL 不应直接复用表所有者。由管理员创建只能登录的角色,并只对目标数据库和模式授权:
CREATE ROLE sql_mcp_reader
LOGIN PASSWORD 'replace-with-strong-secret';
GRANT CONNECT ON DATABASE reporting TO sql_mcp_reader;
GRANT USAGE ON SCHEMA public, reporting TO sql_mcp_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public, reporting TO sql_mcp_reader;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public, reporting TO sql_mcp_reader;
仅对当前表授权并不会自动覆盖未来创建的表。应由对象所有者设置默认权限,或者通过受控流程在新表创建时追加授权:
ALTER DEFAULT PRIVILEGES IN SCHEMA reporting
GRANT SELECT ON TABLES TO sql_mcp_reader;
默认权限属于执行命令的对象创建者。若多个角色会创建表,需要分别配置,不能执行一次就假定永久覆盖所有对象。
除了对象权限,还可以为 PostgreSQL 角色设置默认只读事务:
ALTER ROLE sql_mcp_reader SET default_transaction_read_only = on;
这是一层额外保护,但不能替代 REVOKE 和最小 GRANT。超级用户、特定函数或安全定义者对象可能绕过普通预期。不要给该角色 CREATE、TEMP、函数执行或角色继承能力,除非经过明确评估。
SQL Server 侧也可将访问限制在只读副本或报告数据库。连接到副本可以减少主库负载和写入风险,但复制延迟意味着 Agent 看到的数据可能不是最新状态,回答中应标明时间和数据源。
execute_query 只接受以 SELECT 或 WITH 开始的查询,并拦截一组写关键词。SQL Server 返回行数默认最多 1000,调用者可请求更高,但单次上限为 5000。返回对象会标记结果是否被截断。
CTE 允许复杂分析,也可能产生昂贵执行计划。只读不等于低成本,笛卡尔积、大范围排序、递归 CTE 和无索引过滤都能消耗 CPU、内存与 I/O。应设置查询超时、行数上限和数据库资源组。
模式探索工具使用参数化系统查询,可减少把模式名、表名直接拼入 SQL 的风险。但任意 SELECT 接口仍应视为高敏感数据出口,因为一次合法查询可能读取大量个人信息或商业数据。
SQL_ALLOWED_SCHEMAS 接受逗号分隔的模式名。设置后,工具调用指定不在白名单中的模式会在查询前被拒绝:
SQL_ALLOWED_SCHEMAS=dbo,reporting
不设置意味着所有模式都可访问。生产环境应显式配置,避免新建模式自动暴露给 Agent。SQL Server 与 PostgreSQL 的系统模式、扩展模式和审计模式也应排除。
白名单只是 MCP 层策略,数据库账户权限仍需同步收紧。如果账户能访问更多模式,应用漏洞可能绕过白名单;如果数据库授权更窄,最终以数据库拒绝为准。
SQL_BLOCKED_TABLES 可隐藏并拒绝直接访问指定的 schema.table:
SQL_BLOCKED_TABLES=dbo.audit_log,hr.salaries
被屏蔽对象会从表、视图和时态表列表中过滤,describe_table 等直接工具也会拒绝。execute_query 会检查原始 SQL 中的表引用,但文本检查不应承担唯一安全责任。
更强做法是在数据库中不给该账户相应 SELECT 权限,或只授予脱敏视图。表黑名单适合额外防误操作,不适合替代数据库级拒绝。
SQL_MASKED_COLUMNS 指定需要在响应中替换为占位符的列:
SQL_MASKED_COLUMNS=dbo.users.ssn,dbo.users.credit_card,dbo.employees.salary
匹配列的原值不会发送给 MCP 客户端,响应中显示遮罩标记。这能减少模型上下文、聊天记录和截图中的敏感数据,但列名匹配必须准确,别名、视图和表达式需要测试。
优先在数据库侧创建只包含允许字段的视图,并让 MCP 账户只读这些视图。应用层遮罩作为第二层保护。任何新列上线时都要经过数据分类,避免敏感字段因配置未更新而暴露。
SQL_MAX_ROWS 是所有工具的硬上限,execute_query 会取调用者 max_rows 与全局上限中的较小值:
SQL_MAX_ROWS=1000
行数限制可以控制上下文体积和误导出规模,但不能限制单行超大文本、二进制编码或查询扫描成本。数据库侧还应设置 statement timeout、结果大小、连接数和资源配额。
让 Agent 使用明确过滤条件、TOP、LIMIT 或分页,并先查询统计信息和索引。不要用反复扩大上限的方式解决分析问题。
本地使用推荐 stdio 模式,在项目级或用户级 MCP 配置中指定构建后的 dist/index.js。项目级配置能把权限限制在特定仓库,更适合敏感数据库。
{
"mcpServers": {
"sql-mcp-reporting": {
"command": "node",
"args": ["/opt/sql-mcp/dist/index.js"],
"env": {
"DB_PROVIDER": "postgres",
"PG_HOST": "pg.example.internal",
"PG_DATABASE": "reporting",
"PG_USER": "sql_mcp_reader"
}
}
}
}
密码不应直接写进会提交的项目配置。通过受控环境或秘密管理器注入,并确认启动 Claude Code 的进程能够读取但不会打印。全局 scope 会让所有项目看到同一 MCP 服务,除非确有需要,不要用于生产数据库。
stdio 由 MCP 客户端直接启动子进程,适合单用户本地环境,减少额外端口。服务必须把协议输出留在标准输出,把启动信息和错误写到标准错误,否则日志会破坏 MCP 消息。
设置 PORT 后可切换到 HTTP 模式,容器示例默认提供 MCP 端点和健康检查。HTTP 适合多个客户端共享或远程部署,但必须增加 TLS、认证、网络白名单、速率限制和反向代理。
不要把容器端口直接暴露到公网。示例 compose 和 docker run 用于启动演示,不是完整生产安全基线。数据库凭据也不能写入镜像历史或可公开读取的 compose 文件。
同一 SQL Server 实例中,多数工具接受可选 database 参数,服务会为不同数据库维护连接池。方便并不等于应该允许 Agent任意跨库,数据库登录必须只映射到批准数据库。
开发和生产应注册为两个独立 MCP 服务,使用不同名称、进程和凭据。名字中明确包含环境,例如 sql-mcp-dev 与 sql-mcp-prod,并在生产实例设置更小的行数上限和更严格白名单。
如果客户端能在同一对话调用两个环境,提示中返回的表名可能导致误选。最安全的做法是让生产只读服务只出现在专门的审计项目中,而不是所有开发会话。
项目会记录所有工具调用,包括被拦截的请求。文件日志按 UTC 日期轮转为逐行 JSON,字段包含时间、工具、数据库、模式、对象、查询哈希、返回行数、遮罩列、是否拦截、原因和耗时。
查询使用哈希而非直接保存全文,有助于减少敏感 SQL 和字面值泄露。数据库名、对象名和运行时间仍可能敏感,日志目录应限制权限并设置保留周期。
还可以把审计记录写入独立 SQL 表。审计写入账户只需要对目标审计表的 INSERT 权限,不应复用主查询账户。最好把审计库放在不同安全域,避免被同一只读客户端访问。
项目当前在文件或 SQL 审计写入失败时把错误写到标准错误,但不会阻止工具返回结果。这种 fail-open 设计保证可用性,却意味着审计不可用时查询仍会继续。
高合规场景应通过外部坚控检查日志文件增长、写入错误和审计数据库延迟,发生故障时由编排系统停用 MCP 服务。不能仅凭“已配置审计”就认为每次调用都有记录。
定期用一个可识别的只读测试调用验证文件与 SQL 两个接收端,并检查时间同步、轮转、磁盘容量和告警。不要在测试中查询真实敏感数据。
第一组测试使用合法 SELECT,确认能列出允许模式、描述允许表并返回受限行数。第二组对黑名单表和非白名单模式调用工具,必须在数据库查询前被拒绝。
第三组提交 INSERT、UPDATE、DELETE、DROP、EXEC 和带 CTE 的写入尝试,确认应用层拒绝。第四组绕过 MCP,使用同一数据库凭据直接连接并尝试写入,必须由数据库权限拒绝。
第五组查询遮罩列,确认原值从未进入客户端响应与审计日志。第六组故意请求超过上限的结果,确认截断标识和硬上限正确。只有两层测试都通过,才能声称部署具备只读保障。
这是最严重错误。应用层过滤一旦失效,管理员账户可以修改所有对象。立即创建专用角色、轮换泄露凭据,并审查历史调用。
该变量在当前项目中只是为未来版本保留,写权限目前不受支持,也不能用它证明只读。真正有效的是应用校验与数据库 GRANT。
留空表示 MCP 层允许所有模式,不是拒绝全部。生产环境应显式填写允许模式,并用数据库权限再次限制。
项目级 MCP 配置可能进入 Git 或被其他工具读取。使用环境注入或秘密存储,轮换已经提交的密码,仅删除 Git 当前文件不足以消除历史泄露。
这会彻底破坏最小权限。宁可禁用该工具或运行隔离的专用元数据实例,也不要让自然语言客户端持有服务器管理员权限。
上线前确认 Node.js 与源码版本固定,依赖已审查,MCP 进程使用普通系统账户;数据库使用专用只读身份,没有写角色、对象所有权或高权限继承;网络只允许必要来源,生产连接启用证书验证。
配置中显式设置允许模式、屏蔽表、遮罩列和最大行数;敏感对象优先由数据库视图和 GRANT 隔离;stdio 与 HTTP 日志不会混入协议流;HTTP 模式具备认证、TLS 和限流。
最后执行合法查询、恶意写入、直接数据库写入、越权模式、黑名单表、遮罩列、行数截断与审计故障测试。记录结果和版本,任何权限或数据库结构变化后重新验证。
SQL MCP 的只读能力不是一个开关,而是一套分层约束。应用过滤负责阻断明显危险 SQL,数据库专用账户负责最终拒绝写入,策略变量限制可见范围,审计系统提供追踪。四层同时生效,SQL Server 与 PostgreSQL 才能以可控方式交给 AI 编程客户端探索。
Ubuntu18.04左侧边栏图标怎么调整大小?
deepin怎么修改dns地址?
AWS Labs 的 SQL Server MCP Server 如何阻止危险写入查询?
ubuntu开始菜单中的图标怎么删除?
Oracle SQLcl MCP Server 可以执行哪些 SQL 和 PL/SQL 操作?
GPT-5.2 使用 high 而非 xhigh Reasoning Effort 时能处理多长的软件任务?