mcpField
J
JDBC MCP Server

JDBC MCP Server

本地服务
github.com数据库15 周前更新

关于 JDBC MCP Server

JDBC MCP Server 通过 JDBC 为 AI Agent 提供关系型数据库的只读访问,支持模式探索、SQL 查询、执行计划和索引分析,并可通过本地持久目录管理多个连接。

主要功能

  1. 01只读 SELECT 查询与模式检查
  2. 02查询计划、统计信息和索引分析
  3. 03内置支持五种数据库引擎
  4. 04单个服务配置多个连接
  5. 05持久化模式与查询目录
  6. 06可独立配置工具组

适用场景

  1. 01探索不熟悉的数据库模式
  2. 02根据数据库记录回答问题
  3. 03检查并优化慢查询
  4. 04审计模式与索引使用情况

MCP 相关

以 stdio 方式运行 MCP 服务,按可配置工具组提供 49 个工具,并支持可选资源。每次工具调用都指定一个已配置的数据库连接。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"igorolv-jdbc": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"JDBC_MCP_RESOURCES_ENABLED",
"ghcr.io/igorolv/jdbc-mcp-server:0.2.0"
],
"env": {
"JDBC_MCP_RESOURCES_ENABLED": "<JDBC_MCP_RESOURCES_ENABLED>"
}
}
}
}
启动命令docker run -i --rm -e JDBC_MCP_RESOURCES_ENABLED ghcr.io/igorolv/jdbc-mcp-server:0.2.0
需要配置的环境变量
JDBC_MCP_RESOURCES_ENABLEDAlso expose catalog-qualified MCP resources for table and column metadata

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

安装包
ocighcr.io/igorolv/jdbc-mcp-server:0.2.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

JDBC MCP Server

CI Release License Java 21 MCP Glama score Listed on mcpservers.org

MCP 服务(stdio),通过 JDBC 提供对关系型数据库的只读访问:架构元数据、SELECT 执行、执行计划、统计信息和索引分析。内置 PostgreSQL、Oracle、SQL Server、Firebird 和 SQLite 方言(已捆绑驱动);其他数据库通过 DatabaseMetaData 和外部驱动提供服务。

目录: 功能 · 典型场景 · 快速入门 · 架构 · MCP 工具 · MCP 资源 · 只读保护 · 服务环境变量 · 构建 · 技术栈 · 故障排除 · 许可证

功能

  • 数据库引擎: PostgreSQL 11+、Oracle 12c+、SQL Server 2012+、Firebird 3+、SQLite;通过 driverPath 支持通用 JDBC。各引擎的功能:支持的数据库。
  • 写入保护: JSqlParser AST 防护(单条 SELECT / WITH / EXPLAIN),并在引擎支持时启用会话级、事务级或文件级只读模式。详情:只读保护。
  • 连接: 在一个 connections.json 中配置任意数量的数据库;每个工具都接受 connection 参数;连接池会在首次使用时创建。不会从环境中读取凭据。
  • 工具: 共 49 个,分为 11 个组,每组都可单独禁用:元数据、查询执行、计划分析、列分布和选择性、表和索引统计、架构上下文、基准测试、使用目录。参考:MCP 工具。
  • 本地目录: 每个连接对应一个 SQLite 文件,包含持久化的结构快照和已知应用程序查询的索引(使用目录)。
  • 客户端: 支持 stdio 传输的任意 MCP 客户端;docs/clients.md 中提供 Claude Code、Codex CLI、OpenCode、VS Code、Copilot CLI、Cursor、Claude Desktop 和 Qwen Code 的配置示例。

常见场景

Agent 会自行选择工具;以下是它通常遵循的调用链。每种工具都在 MCP 工具中有说明。

场景示例请求工具
回答数据问题“上个月各地区分别发出了多少订单?”queryContext 或 schemaBrief → describeTable → findJoinPaths → validateQuery → executeQuery
探索陌生的架构“billing 架构包含什么?其中的表有什么关联?”schemaBrief → tableContext → sampleRows → schemaGraphDot
执行查询前检查“这个报表查询正确吗?它实际读取了哪些表?”inspectQuery → queryLint → resolveQueryLineage → analyzePlan
加快慢查询“这个查询为什么这么慢?添加哪个索引会有帮助?”analyzePlan → tableStats、indexStats → estimateSelectivity、columnDistribution、joinCardinality → benchmarkQuery
审核索引和架构“找出 orders 架构中缺失和冗余的索引。”fkIndexCoverage、redundantIndexes、unusedIndexes、schemaLint
从现有应用的 SQL 中学习“应用通常如何联接 customers 和 invoices?”findQueriesByTable、findQueriesByColumn、observedRelationships

快速入门

1. 获取 jar — 从最新版本下载 jdbc-mcp-server.jar(需要 JDK 21+;已捆绑所有 JDBC 驱动),或自行构建:

./gradlew bootJar   # → build/libs/jdbc-mcp-server.jar

没有本地 JDK?请改用 Docker 镜像 ghcr.io/igorolv/jdbc-mcp-server——参见 Docker。

2. 描述数据库,在 ~/.jdbc-mcp-server/connections.json 中填写(Windows 上为 %USERPROFILE%\.jdbc-mcp-server\connections.json,Docker 镜像中为 /data/connections.json)——每个数据库对应一项,以连接名称为键:

{
  "connections": {
    "orders": {
      "url": "jdbc:postgresql://db.example.com:5432/orders",
      "username": "ai_readonly",
      "password": "secret",
      "defaultSchema": "public",
      "description": "Order service — customers, orders, shipments",
      "structureSnapshotSchemas": ["public", "nsi"]
    },
    "billing": {
      "url": "jdbc:oracle:thin:@//oracle.example.com:1521/BILLING",
      "username": "AI_READONLY",
      "password": "${BILLING_DB_PASSWORD}",
      "defaultSchema": "BILLING_OWNER",
      "description": "Legacy billing (Oracle)"
    },
    "crm": {
      "url": "jdbc:sqlserver://sql.example.com:1433;databaseName=crm;encrypt=true",
      "username": "ai_readonly",
      "password": "secret",
      "defaultSchema": "dbo",
      "description": "CRM (SQL Server)"
    },
    "legacy": {
      "url": "jdbc:firebirdsql://fb.example.com:3050//var/lib/firebird/data/app.fdb",
      "username": "SYSDBA",
      "password": "secret",
      "description": "Pre-2010 warehouse app (Firebird)"
    },
    "archive": {
      "url": "jdbc:firebirdsql:embedded:/srv/data/archive-copy.fdb?nativeLibraryPath=/opt/firebird/lib",
      "username": "SYSDBA",
      "password": "secret",
      "description": "Copy of the warehouse archive, opened in-process (Firebird embedded)"
    },
    "analytics": {
      "url": "jdbc:sqlite:/srv/data/analytics.db",
      "description": "Nightly analytics extract (SQLite)"
    },
    "shop": {
      "url": "jdbc:mysql://mysql.example.com:3306/shop",
      "username": "ai_readonly",
      "password": "secret",
      "driverPath": "drivers/mysql-connector-j-9.1.0.jar",
      "description": "Web shop (MySQL, generic JDBC)"
    }
  }
}
  • url 是唯一必填字段;程序会根据前缀检测数据库引擎。其他 URL 需要通过 driverPath 指定驱动 jar,并以通用 JDBC方式提供服务。
  • description 会由 listConnections 返回,Agent 会据此选择数据库;请说明用途,并注明限制(“PRODUCTION — 查询请保持精简”)。
  • archive 会在进程内打开本地 Firebird 文件:nativeLibraryPath 指向包含相应引擎及插件的 libfbclient.so / fbclient.dll 所在目录。请将其指向该文件的副本——参见 Firebird。
  • 请使用只读数据库用户:这是唯一不依赖此服务的保护措施。确保文件仅对其所有者可读。

所有字段、命名规则、${VAR} 密钥以及同一服务的多个用途: docs/connections.md。

3. 注册服务,并在 MCP 客户端配置中不填写数据库设置:

{
  "command": "java",
  "args": ["-jar", "<absolute-path>/jdbc-mcp-server.jar"],
  "env": {}
}

对于 Claude Code 和 Codex CLI,只需运行一条命令:

claude mcp add --scope user jdbc -- java -jar /path/to/jdbc-mcp-server.jar
codex mcp add jdbc -- java -jar /path/to/jdbc-mcp-server.jar

OpenCode、搭配 Copilot 的 VS Code、Copilot CLI、Cursor、Claude Desktop、Qwen Code,以及适用于所有客户端的提示:docs/clients.md。

4. 试用。 用日常语言向 Agent 提问:

  • “你能连接哪些数据库?”——它会调用 listConnections,列出 connections.json 中的各项及其说明。
  • “orders 中有多少张表?”——它会对该连接调用 listTables 并统计表数。

如果首次调用数据库失败,请参阅 检查配置。

架构

 MCP client (Claude Code, Codex, VS Code, Cursor, ...)
      |  JSON-RPC over stdin / stdout, no network port
      v
+- jdbc-mcp-server: one JVM, started by the client ------------------------------+
|                                                                                |
|  MCP layer          49 tools in switchable groups, optional resources          |
|      |              every call names its `connection`                          |
|      v                                                                         |
|  Connection registry  <-- connections.json, read once at startup               |
|      |              a connection is built on its first call, then reused       |
|      v                                                                         |
|  Per-connection context                                                        |
|   +- read-only guard (JSqlParser AST) -> SQL executor (row cap, timeout)       |
|   +- dialect: PostgreSQL, Oracle, SQL Server, Firebird, SQLite, generic        |
|   +- metadata, statistics, plan parser and analyzer                            |
|   +- local catalog <data-dir>/<name>/<name>.db (SQLite, WAL):                  |
|   |     structure snapshot + usage index of known queries                      |
|   +- Hikari pool of read-only JDBC connections -----------------> database     |
+--------------------------------------------------------------------------------+
  • 一个进程,多个数据库。 客户端将服务作为子进程启动,并通过 stdio 与其通信。数据库配置来自 connections.json;只有当工具调用首次指定某个连接时,才会创建该连接的连接池、本地目录和服务,因此某个数据库不可用或配置错误,只会影响针对它发起的调用。
  • SQL 执行路径。 每条语句都会先经过只读检查,然后通过只读 JDBC 连接执行,并受该连接的行数上限和超时设置约束。引擎级保护措施详见只读保护。
  • 方言。 每种引擎都有自己的元数据查询、执行计划和统计信息实现;其他数据库则通过 DatabaseMetaData 和可移植 SQL 以通用模式提供服务,详见支持的数据库。
  • 本地目录。 结构元数据按连接持久化在 SQLite 文件中,且不会过期:describeTable、架构上下文工具和 searchObjects 会从中读取已覆盖的架构,否则回退到实时数据库。同一文件还存储使用索引。实时统计信息、样本和执行计划从不缓存。详见持久化结构快照和使用目录。
  • 执行模型。 单个 stdio 会话中的工具调用按顺序运行。Spring AI 2.0.1 使用的 MCP Java SDK 2.0.0 在多个并发执行的工具同时完成时可能丢失响应,因此在 SDK 修复此问题前,服务会保持 immediateExecution(true)。客户端的 notifications/cancelled 不会传递给 JDBC 的 Statement.cancel();已配置的 queryTimeoutSeconds(或工具调用的 timeoutSeconds 覆盖值)仍是运行中 SQL 语句在服务端的超时限制。

MCP 工具

以下按用途对 49 个工具进行了分组。

每个工具都将 connection 作为第一个必需参数,用于指定要操作的数据库——即使部署中恰好只提供一个数据库也是如此。listConnections 会列出各连接的名称。详见在一个服务中使用多个数据库。

工具组

工具按组组织,可通过 JDBC_MCP_TOOLS_* 标志分别启用或关闭。默认情况下,所有组均已启用,因此开箱即可使用完整工具集。关闭工具组会缩减 tools/list 清单;对于上下文较小的本地模型,这一点很重要,否则首次调用前就会被工具架构淹没。

组标志默认值工具
元数据JDBC_MCP_TOOLS_METADATA启用listSchemas、listTables、describeTable、getTriggerDefinition、getViewDefinition、listRoutines、getRoutineDefinition、listSequences、searchObjects
查询JDBC_MCP_TOOLS_QUERY启用executeQuery
管理JDBC_MCP_TOOLS_ADMIN启用rebuildCatalog
示例JDBC_MCP_TOOLS_SAMPLE启用sampleRows
查询分析JDBC_MCP_TOOLS_ANALYSIS启用explainQuery、analyzePlan、validateQuery、inspectQuery、queryLint、resolveQueryLineage
分布JDBC_MCP_TOOLS_DISTRIBUTION启用columnStats、columnDistribution、columnHistogram、nullRatio、estimateSelectivity、joinCardinality
统计信息JDBC_MCP_TOOLS_STATS启用tableStats、indexStats、unusedIndexes、redundantIndexes、fkIndexCoverage
基准测试JDBC_MCP_TOOLS_BENCHMARK启用benchmarkQuery、timedQuery
使用情况目录JDBC_MCP_TOOLS_USAGE启用usageCatalogStatus、getQuery、listQueries、findQueriesByTable、findQueriesByColumn、observedRelationships、listKnownTags、listKnownDomains、listKnownKinds、invalidateUsageCatalogCache
架构上下文JDBC_MCP_TOOLS_SCHEMA_CONTEXT启用tableContext、findJoinPaths、schemaLint、schemaBrief、schemaGraph、queryContext、schemaGraphDot
连接JDBC_MCP_TOOLS_CONNECTIONS启用listConnections

每个标志都接受 true / false。对于上下文较小的本地模型,请关闭不需要的组——例如,将其余组设为 false,仅保留“元数据 + 查询”——以将清单缩减为最精简的“探索架构并运行查询”工具集。下文将介绍每个工具,不受其所属组的影响。

查询
工具描述
executeQuery执行 SELECT、WITH 或 EXPLAIN 语句。参数:sql、params(用于 ? 的数组)或 namedParams(用于 :name 的对象)、limit、timeoutSeconds。如果达到行数上限,结果会标记为 truncated: true
explainQuery返回执行计划。PostgreSQL:EXPLAIN (FORMAT TEXT)。Oracle:EXPLAIN PLAN FOR 加上 DBMS_XPLAN.DISPLAY。SQL Server:在同一会话中执行 SET SHOWPLAN_TEXT ON。参数可通过 params(?)或 namedParams(:name)传入。在 PostgreSQL 上,analyze=true 会启用 EXPLAIN ANALYZE;请谨慎使用,因为查询实际上会被执行。SQL Server 目前只返回估算计划
analyzePlan返回面向大模型的精简计划摘要,而非大量原始计划数据:成本最高的节点、大型表上的全表扫描、估算误差(规划器估算与实际情况之间的差异;在 PostgreSQL 上需要 analyze=true)、外层输入较大且存在风险的嵌套循环,以及磁盘排序溢出。PostgreSQL:EXPLAIN (FORMAT JSON) / EXPLAIN ANALYZE。Oracle:EXPLAIN PLAN 加上 PLAN_TABLE(此处 Oracle 提供的是静态计划,因此会忽略 analyze)。SQL Server:SET SHOWPLAN_XML ON 估算计划。参数可通过 params(?)或 namedParams(:name)传入
validateQuery验证语法但不执行:通过只读保护和驱动程序的 prepareStatement 进行验证;解析成功时,还会提供从 JSqlParser 派生的 inspection 摘要。参数可通过 params(?)或 namedParams(:name)传入。适用于大模型自我纠错
inspectQuery通过 JSqlParser 解析 SQL,不访问数据库,并返回 AST 摘要:表、别名、CTE、选择项、连接、谓词、排序依据、列、参数、特性和解析器警告
queryLint解析 SQL,并结合 AST 与元数据、索引及 FK 检查。返回建议性警告,例如表或列未知、SELECT *、连接缺少条件、FK 缺少支持索引,以及谓词/排序依据中的列不是索引的前导列。不会执行 SQL
resolveQueryLineage解析查询引用的直接对象,并递归展开数据库视图/物化视图,找到底层物理表。函数/过程展开尽力而为:如果例程源代码中包含嵌入的 SELECT / WITH 语句,则会提取这些语句。参数:sql、schema、expandViews、expandRoutines、maxDepth
基准测试

用于测量查询的实际开销,让大模型无需根据计划猜测,并能查看实际耗时(毫秒)和缓冲区计数器。

工具描述
benchmarkQuery运行查询 coldRuns + warmRuns 次(默认为 1 次冷运行 + 3 次热运行),并返回热运行的墙钟时间 min、median 和 max;冷运行会单独报告。参数可通过 params(?)或 namedParams(:name)传入。limit 和 timeoutSeconds 必填;会拒绝无界查询。返回最后一次结果的大小(row_count、列、truncated),而非结果行
timedQuery在常规 executeQuery 的基础上,增加墙钟时间 elapsed_ms。参数可通过 params(?)或 namedParams(:name)传入。在 PostgreSQL 上,它还会在查询前后采集 pg_stat_statements 快照;差异会显示哪些查询 ID 增加了 calls、total_exec_time_ms、rows、shared_blks_hit 和 shared_blks_read,从而清楚地显示服务器的耗时去向。需要 pg_stat_statements(CREATE EXTENSION pg_stat_statements;,以及 shared_preload_libraries);如果缺少该扩展,则返回 pg_stat_statements.available: false
元数据
工具描述
listSchemas列出架构。默认隐藏系统架构;使用 includeSystem=true 显示所有架构
listTables列出架构中的表和视图。参数:schema、namePattern(支持 % / _)、types(逗号分隔,例如 TABLE,VIEW,MATERIALIZED VIEW)
describeTable一次调用即可获取完整的对象描述:列、主键、唯一约束、索引、传出/传入外键、CHECK 约束及允许值,以及精简的触发器元数据
getTriggerDefinition获取指定触发器的触发器主体。参数:schema、table、trigger
getViewDefinition获取视图的 SQL 定义
listRoutines列出架构中的函数、过程和程序包
getRoutineDefinition获取函数或过程的源代码。在 Oracle 上,所有 ALL_SOURCE 行都会按顺序拼接
listSequences列出一个架构中的序列;省略 schema 时则列出所有架构中的序列
searchObjects在非系统表、视图、例程、序列和同义词中执行不区分大小写的子字符串搜索
架构上下文

用于快速了解架构和编写 SQL 的高级工具。LLM 无需针对每张表手动依次调用 listTables -> describeTable -> sampleRows,而是可以通过一次调用获取可直接使用的 上下文:表、列、关系、约束和示例行。

工具描述
tableContext获取一张表的相关上下文:表本身、外键父表,以及可选的子表和关系边。外键遍历深度使用请求的值(默认值为 1,最大值为 4)。参数:schema、table、depth、includeIncoming、includeStats、includeObserved
findJoinPaths查找两张表之间通过外键连接的 JOIN 路径。图会沿两个方向遍历,每条边都包含 joinCondition 和带类型的 evidence 信息包(见下文的 边证据)。参数:fromSchema / fromTable、toSchema / toTable、maxDepth(默认值/最大值为 4)、maxPaths(默认值为 5,最大值为 25)、scanLimit(默认值/最大值为 300)、includeObserved
schemaBrief用于编写 SQL 的纯文本完整架构映射:列出所有匹配的表/视图及其列数、PK、传入/传出关系数、类似键的列、中心/孤立表,以及数量受限的关键外键关系。相关表未知时请先使用此工具;然后使用 queryContext 获取详细上下文。参数:schema、terms(可选的子字符串搜索)、maxTables(安全上限;默认值为 2000,最大值为 5000)
schemaGraph架构关系图指标:包含节点的入度/出度和分类、边、中心表、孤立表、连通分量及环路提示。可选包含两张表之间的最短路径
schemaLint架构检查审计:检查缺失的主键、没有索引的外键、外键类型不匹配、可空的唯一约束、没有 CHECK 约束的状态/类型列、孤立的 *_id 列、缺失的备注、孤立表和宽表。可通过 checks 配置检查项
queryContext根据搜索词和/或明确指定的表构建精简的 SQL 编写上下文。使用声明的架构名称/注释,以及可用时的使用目录语义证据,查找相关表和列;包括约束及允许值、所选表之间的关系和 JOIN 路径,并可选包含示例行(每张表最多 3 行)
schemaGraphDot以 DOT/Graphviz 格式表示架构关系图。节点为包含所有列及类型的表(内联标记 PK 和 FK),边包含 JOIN 条件。参数:schema、tables(可选的逗号分隔筛选项)
边证据

如果未设置 includeObserved,且启用了本地使用目录(见下文 使用目录),则 tableContext / findJoinPaths 会自动启用此选项。随后,每条关系边都会携带一个类型化的三层 evidence 证据包。每一层都可独立省略,没有相关信号时便不会出现:

  • declaredSchema — 该关系是数据库目录中声明的外键。包含外键名称和列列表。
  • observedQuery — 存储的应用查询中出现了等值连接对。包含 joinSupport(不同查询的数量)和 queryUids(最多 5 个相关 uid)。
  • semanticUsage — 同时涉及两张表的查询所共享的术语:业务领域、业务对象和输出标签,以及共同出现的查询数量和 uid 预览。此层只会为现有边添加信息,不会提出新的关系。
{
  "relationshipType": "foreignKey",
  "fromTable": "ORDERS", "fromColumns": ["CUSTOMER_ID"],
  "toTable": "CUSTOMERS", "toColumns": ["ID"],
  "evidence": {
    "declaredSchema": { "foreignKeyName": "FK_ORDERS_CUSTOMER", "fromColumns": ["CUSTOMER_ID"], "toColumns": ["ID"] },
    "observedQuery": { "joinSupport": 18, "queryUids": ["SHOP/InvoiceReport.json#header"] },
    "semanticUsage": {
      "sharedBusinessDomains": [{ "value": "Customers", "support": 12, "queryUids": [...] }],
      "sharedBusinessObjects": [{ "value": "Invoice payer", "support": 4, "queryUids": [...] }],
      "sharedOutputLabels":     [{ "value": "Payer name",   "support": 3, "queryUids": [...] }],
      "coOccurringQueryCount": 22,
      "coOccurringQueryUids": [...]
    }
  }
}

仅在存储查询中出现的等值连接对(没有声明外键)会作为新边追加,连接范围内已有的表,并标记为 relationshipType: "observed" 和 undirected: true。复合(多列)外键会获得 declaredSchema 层,但在本次迭代中不会匹配观测到的连接对。schemaBrief、schemaGraph 和 queryContext 仅展示已声明的外键关系。

证据模型

架构上下文层将三种知识来源分别保留:

  • declared_schema - 实时数据库内省:表、列、PK/FK、索引、约束、注释和统计信息。
  • observed_query - 已索引的查询目录:哪些存储的应用/报表查询引用了某张表或某列,以及其 SQL 上下文(select、where、join、order_by、having)。
  • semantic_usage - 由适配器提供的业务含义:查询领域/标签/标签文本、输出标签、参数说明、字段用法、渲染后的业务对象和置信度。

在 tableContext 中,现有表字段是精简的 declared_schema 视图。启用 includeObserved 且使用目录可用时,每张表还会包含一个 evidence 区块:

{
  "evidence": {
    "observedQuery": {
      "queryCount": 12,
      "queryUids": ["SHOP/reports/customer-card#main"],
      "columns": [
        {"column": "STATUS", "queryCount": 5, "contexts": [{"value": "where", "support": 4}]}
      ]
    },
    "semanticUsage": {
      "businessDomains": [{"value": "Customers", "support": 8}],
      "businessTags": [{"value": "customer", "support": 6}],
      "queryLabels": [{"value": "Customer card", "support": 3}],
      "outputLabels": [{"value": "Customer name", "support": 4}],
      "businessObjects": [{"value": "Customer card", "support": 3}]
    }
  }
}

服务将这些内容视为证据,而非单一的规范业务模型。不同查询可以合理地为同一物理表或列赋予不同的业务角色。

queryContext 也会将 semantic_usage 用作发现信号。用户传入自然语言 terms 时,服务会搜索使用目录中的领域、标签、查询标签文本、输出标签和业务对象。匹配的表会返回在 semanticMatches 中,并且优先于针对实时架构元数据的名称/注释回退扫描。这样一来,即使现有报表将 customers.name 显示为“付款人姓名”,术语“付款人”也能找到物理表 CUSTOMERS。

使用目录

已检查数据库中已知 SQL 用法的目录,可选包含业务上下文:带说明的参数、注明含义的输出列,以及每项输出在使用该内容的制品中的显示位置(BI Publisher 报表中的 Excel 单元格、仪表板小组件等)。

使用记录有两个来源。基于文件的使用记录来自包含规范 QueryUsage JSON 记录的目录/JSON 文件/zip 归档。数据库原生使用记录则由已连接架构中的视图、例程和触发器自动生成。运行时,服务会解析这些记录,并构建持久化的 SQLite 索引,将提取出的表/列/等值连接对作为事实。对于基于文件的记录,JSON 文件始终是权威来源;原生记录则会根据实时元数据刷新。 用途。 元数据工具回答“有哪些表和列”;使用情况目录回答“应用如何使用它们”。它支持诸如“哪些报表引用了此列”和“此输出字段带有什么业务标签”等查询,并为关系 evidence 包中的 observedQuery 和 semanticUsage 层提供数据,因此存储查询中发现的等值连接会与已声明的外键并列显示(例如,“这两个列在 17 个已存储的报表查询中进行了连接”,并附带其 uid)。

标识。 每个查询都以 (source.kind, source.path, source.unit) 为键。诊断信息和证据会按以下格式显示此键:

{source.kind}/{source.path}#{source.unit}

如果没有 unit,则省略 #unit 后缀。示例:

bi-publisher-report/reports/customers/CustomerCard.xdo#CUST
manual/manual/ad-hoc-2026-05-01
java-dao/src/main/java/com/example/shop/OrderDao.java#findByCustomer

source.kind 和 source.unit 不得包含 / 或 #;source.path 不得包含 #。对于重复的 source 键,在该索引构建中以第一条记录为准。

文件存放位置。 默认目录目录为 <data-dir>/<connection>/usage-catalog。在 connection 上将 usageCatalogPaths 配置为其他目录、.json 文件或 .zip 压缩包的列表。目录会递归扫描 *.json;zip 压缩包会扫描其中的 JSON 条目。设置 usageCatalogEnabled: false 可禁用目录。此时 usageCatalogStatus 会报告 catalogEnabled: false;其他公共使用情况工具会返回 argument 错误,并说明如何启用目录。

数据库原生使用情况。 目录还会索引默认 schema 中受支持的数据库对象:

  • 视图 / 物化视图,作为 source.kind="database-view" 或 source.kind="database-materialized-view";
  • 函数和过程,在引擎会报告其区别时,作为 source.kind="database-function" / source.kind="database-procedure";
  • 触发器,作为 source.kind="database-trigger"。

视图通常会提供完整解析的表、列和连接证据。例程和触发器主体因引擎而异,因此索引器首先使用基于 ANTLR 的过程式预提取器查找嵌入的 SELECT / WITH / INSERT / UPDATE / DELETE / MERGE 语句,然后将这些语句送入现有的 JSqlParser 分析流程。如果未找到嵌入的语句,仍会保留该对象作为溯源记录。使用 connection 上的 usageNativeSchemas 扫描指定 schema。

持久化索引。 服务启动时绝不会构建使用情况索引。首次查询使用情况目录时,会从文件记录和数据库原生对象同步构建索引,并写入本地 SQLite <catalog>.db。源文件和数据库对象仍是权威数据。修改它们后,请使用 invalidateUsageCatalogCache;该操作会清除已索引的使用情况行,下一次查询时会重新构建索引。

仅本地写入。 使用情况目录绝不会写入被检查的 JDBC 数据库。现有的 ReadOnlyGuard 和 connection 级保护措施仍然有效。

类型化载荷。 规范的 source、parameters[]、outputs[]、fieldUsages[] 及嵌套对象由 JSON Schema 描述(字段名称、类型、描述、枚举值)。文件索引使用相同的记录类型(usage/format/ 中的 QueryUsage 及相关类型)。

与来源无关的规范 JSON 格式记录在 docs/usage-catalog-format.md 中;其 JSON Schema 位于 src/main/resources/schemas/query-usage-record.schema.json,示例位于 examples/usage/ 下。针对特定来源的适配器应输出此规范格式,而不是在 JDBC MCP 服务内部实现。

工具描述
usageCatalogStatus当前目录状态(not_started、indexing、ready、failed 或 invalidated)、启用标志和已配置的来源
invalidateUsageCatalogCache清除运行时索引。下次查找时,会根据已配置的文件和数据库原生对象同步重建索引
getQuery根据 sourceKind、sourcePath 和可选的 sourceUnit 选出的完整记录:标头、参数、解析后的表/列/连接对、输出和字段使用情况
listQueries支持分页和可选筛选条件的列表:sourcePath(LIKE — 可使用 %/_)、sourceKind、businessDomain、tag、parseStatus、searchText、limit、offset
findQueriesByTable引用了指定表的所有目录查询。通过别名解析后的大写表名进行不区分大小写的匹配。可选的 schema 筛选条件
findQueriesByColumn引用了指定列的所有目录查询,并提供引用的 SQL context(select/where/join/order_by/having)。可选的 schema 和 table 筛选条件
observedRelationships汇总已存储查询中观察到的等值连接对,按 (left_table.left_column = right_table.right_column) 分组,并提供 support 计数和贡献查询的 UID。不包含非等值连接(BETWEEN、基于函数的连接)。相同数据也会提供给 tableContext/findJoinPaths 中关系 evidence 包的 observedQuery 层
listKnownTags当前目录中使用的标签及其查询数。方便 Agent 在多次导入调用中复用稳定的词汇表
listKnownDomainsbusinessDomain 值的相同信息
listKnownKinds当前目录中使用的来源类型及其查询数。帮助 Agent 找出 listQueries 的 sourceKind 筛选条件可用值

解析。 建立索引时,会通过解析器的别名映射低成本地解析表/列限定符,并将其转为大写以进行不区分大小写的匹配。SQL 中显式指定的架构(SCHEMA.TABLE)会按原样保留。未限定架构的表引用会在建立索引时根据实时 JDBC 架构进行解析:只有一个匹配项时填入架构;有多个匹配项时标记为 ambiguous;没有匹配项时则保持 unresolved。

目录管理
工具描述
rebuildCatalog为逗号分隔的 schemas(或已配置/默认范围)重建持久化结构快照和使用情况索引,检查点化 SQLite WAL,并返回可分发的 <catalog>.db 路径及其所针对的连接

此工具只会写入本地目录,不会修改被检查的数据库。

连接
工具描述
listConnections列出此服务提供的数据库:name(要传入 connection 的值)、description、引擎类型、默认架构、本地目录文件是否已存在,以及连接池是否已在此进程中创建

listConnections 只读取配置和本地文件系统,不会打开数据库连接,因此即使部分已配置的数据库不可用,它仍能返回结果。在陌生的安装环境中,这是值得首先调用的工具。

持久化结构快照

结构元数据(列、键、索引、外键、视图、例程、触发器、序列)保存在本地 SQLite <catalog>.db 文件中的持久化结构快照中(与用量目录位于同一数据库文件,路径为 <data-dir>/<catalog>/)。SQLite 以 WAL 模式运行,因此 Codex、Claude 和其他本地 Agent 进程可以并发使用同一目录。这能加快重复调用 tableContext、findJoinPaths、schemaLint、schemaGraph、queryContext、describeTable、searchObjects 和用量目录重新解析器的速度。tableStats、indexStats、columnStats 和 sampleRows 等统计工具不会缓存,其计数值是实时的。

该快照是权威数据(“永久缓存”)——没有 TTL 或过期检测。快照会延迟填充(describeTable 会持久化其加载的每张表),也可以使用 rebuildCatalog 工具预先加载整个架构;该工具会将结构快照和用量索引构建到一个可分发的 <catalog>.db 文件中。rebuildCatalog 在返回前会检查点 WAL。要清除目录,请先停止所有服务进程,再删除 <catalog>.db 及相邻的 <catalog>.db-wal / <catalog>.db-shm 文件。

现有的 H2 <catalog>.mv.db 文件不会转换或删除。首次启动 SQLite 时,服务会创建新的 <catalog>.db、记录一条警告,并保留旧文件;运行 rebuildCatalog 以填充新目录。

配置:

  • structureSnapshotSchemas - 完整重建时预先加载的架构(为空 → 使用默认架构)。
  • structureSnapshotOracleColumnQueryTimeoutSeconds - 仅适用于 Oracle 的超时设置,用于完整重建期间由 DBMS_XMLGEN 支持的批量列/默认值查询(默认值为 300;0 表示禁用)。

两者都是 connections.json 中的连接级字段。

数据探索
工具描述
sampleRows返回表或视图中的若干行(根据数据库使用 LIMIT / FETCH FIRST / TOP)。参数:schema、table、limit(默认值为 10,最大值为 100)
选择性与分布
工具描述
columnStats基本列统计信息:total_rows、non_null_rows、distinct_values、min、max。只需了解极值时,可进行一次低开销聚合查询

columnStats 仅报告极值。其他工具则回答“这个谓词的选择性有多高?”以及“该列中的值分布有多偏斜?”,这些信息能帮助大模型有意义地选择索引或改写 JOIN。

工具描述
columnDistribution返回列中出现频率最高的前 N 个值及其占比。揭示数据偏斜,例如 70% 的行满足 status='OK',此时仅对 status 建立索引并无用处。参数:schema、table、column、topN(默认值为 20,最大值为 1000)
columnHistogram返回 P25 / P50 / P75 / P90 / P95 / P99 百分位数,以及 min、max 和空值计数。使用 SQL:2003 WITHIN GROUP:数值类型使用 percentile_cont,其他所有类型(包括日期、时间戳和文本)使用 percentile_disc
nullRatio扫描一次,统计表中每列的空值/非空值数量。列按 null_ratio 降序排列。sparse=true 会标记空值超过 50% 的列,这些列可能适合创建部分索引
estimateSelectivity无需执行查询,使用 EXPLAIN 和 SELECT 1 FROM t WHERE <predicate> 估算谓词会返回多少行。返回估算行数、未应用筛选条件时的基准行数以及选择性。适用于在复合索引中将选择性最高的谓词放在前面
joinCardinality无需执行 JOIN,估算其输出行数。返回规划器估算值、两侧的行数以及 selectivity_vs_cartesian。支持 INNER、LEFT、RIGHT 和 FULL
对象统计

这些工具可为大模型提供对象规模和健康状况信号;缺少这些信息,优化建议就只能靠猜测。数据来自系统目录(pg_class、pg_stat_*、ALL_TABLES、ALL_INDEXES、DBA_SEGMENTS),并在 Java 端汇总。

工具描述
tableStats表和索引的字节大小、估算行数、PostgreSQL 上的死元组、上次 vacuum/analyze 的时间,以及 seq/idx 扫描计数器。在 Oracle 上,如果有数据,还会包括尽力获取的 DBA_SEGMENTS 数据
indexStats每个索引的大小、扫描计数器、列、是否唯一/主键,以及索引类型。PostgreSQL 扩展信息:idx_tup_read/fetch、pg_get_indexdef。Oracle 扩展信息:distinct_keys、clustering_factor、blevel、leaf_blocks、last_analyzed
unusedIndexesPostgreSQL 上扫描次数为零的索引(pg_stat_user_indexes)。不包括 PK 和 UNIQUE 索引。在 Oracle 上,由于 ALL_INDEXES 不提供使用计数器,因此会返回诊断说明;需要使用 DBA_INDEX_USAGE 12.2+,或通过 ALTER INDEX ... MONITORING USAGE 使用 V$OBJECT_USAGE
redundantIndexes列列表严格为同一表上另一个索引列列表前缀的索引。不会报告唯一索引,因为删除它们会移除约束。索引类型必须相同
fkIndexCoverage子表端缺少支持索引的外键,这是导致缓慢 DELETE / UPDATE CASCADE 和缓慢 JOIN 的常见原因。结果包含可直接用于 CREATE INDEX 的 suggested_index_columns

所有工具均为只读;不会修改数据。

MCP 资源

除了工具之外,服务器还可以将目录作为 MCP 资源发布,供允许用户将表的描述附加到上下文中的客户端使用。资源默认关闭;设置 JDBC_MCP_RESOURCES_ENABLED=true 即可注册资源。无论是否启用,工具都相同。

每个可用连接都会发布一个资源和两个资源模板:

URI名称内容
jdbc-mcp://catalog/<catalog>/manifest<catalog>/manifest数据库类型、结构快照的版本、构建时间和涵盖的架构,以及下方两个模板
jdbc-mcp://catalog/<catalog>/schemas/{schema}/tables/{table}<catalog>/tabledescribeTable 返回的内容:列、键、索引、约束、关系、触发器
jdbc-mcp://catalog/<catalog>/schemas/{schema}/tables/{table}/columns/{column}<catalog>/column单列信息,包括其主键位置、唯一约束、索引、出站和入站外键,以及 CHECK 约束
  • <catalog> 是连接名称,采用 UTF-8 百分号编码(ssj@dev 会变为 ssj%40dev)。它在每个连接中固定不变,不是模板参数:读取时会根据 URI 解析对应连接,因此无论是在同一服务器的多个连接之间,还是在多个已注册实例之间,URI 都不会指向错误的数据库。架构、表和列的片段会进行百分号编码,并保留大小写。
  • 不会列出表。 resources/list 只包含清单;否则,拥有数千张表的架构会让它变成目录转储。客户端通过对模板参数调用 completion/complete 来发现名称:先是 schema,然后是 table(给定 schema),最后是 column(给定两者);匹配时不区分大小写,前缀匹配结果每次最多返回 100 个,若还有更多结果,则会设置 hasMore。
  • 补全结果来自本地目录,不会访问数据库。连接尚无目录时不会返回任何结果,清单中的快照版本为 0;通过 rebuildCatalog 构建的目录会立即生效,无需重启。无论目录是否存在,表和列的读取都可正常工作:与 describeTable 一样,它们会从快照中返回结果,并在必要时回退到实时数据库。
  • 元数据。 每次读取都会附带 _meta,其中包含 catalog、resourceSchemaVersion、snapshotVersion,以及目录存在时的 snapshotBuiltAt。
  • 错误使用 MCP 错误代码:不存在的表或列返回 -32002(资源未找到,data.uri 中包含 URI);格式错误的 URI 返回 -32602(参数无效)。

只读保护

服务器绝不会写入被检查的数据库,也不会依赖单一机制来实现这一点:

  • JSqlParser AST 防护只允许通过单条 SELECT、WITH 或 EXPLAIN 语句,其他语句一律不允许;
  • 每个 JDBC 连接都是只读的,且 PostgreSQL、Firebird 和 SQLite 会在数据库内部强制执行只读(只读会话或事务,或通过 open_mode=1 打开文件);
  • 数据库凭据保存在 connections.json 中,绝不会放在 MCP 客户端配置或环境变量中,因此 Agent 无法轻易绕过服务器,直接使用 psql 或 sqlplus。

最可靠的保障是使用只读数据库用户。各数据库引擎的保护层、适用于 PostgreSQL、Oracle 和 SQL Server 的 GRANT 代码片段、何时可以关闭防护,以及凭据为何存放在文件中,详见:docs/read-only.md。工具错误(包括防护返回的 rejected)列于 docs/errors.md。

服务端环境变量

数据库、凭据以及所有因数据库而异的设置都存放在 connections.json 中——刻意 不放在环境变量中。环境变量仅配置服务端进程本身:

变量必需描述
JDBC_MCP_CONNECTIONS_FILE否描述此服务端提供的具名连接的 JSON 文件路径;默认为 <data-dir>/connections.json。文件缺失或为空时,服务端会在没有连接的情况下启动(并记录警告);文件格式错误则会导致启动失败
JDBC_MCP_DATA_DIR否服务端本地数据的根目录,默认为 ~/.jdbc-mcp-server。每个连接都会在该目录下拥有自己的子目录
JDBC_MCP_RESOURCES_ENABLED否是否公开带目录限定的清单和表/列资源模板,并提供参数补全;默认为 false
JDBC_MCP_TOOLS_*否各工具组的独立开关,用于控制哪些工具会出现在 tools/list 中。所有工具组默认均为 true;将某个工具组设为 false 即可隐藏它(适用于上下文较小的模型)。请参阅工具组

连接自身的设置——URL、凭据、默认架构、超时、行数上限、连接池大小、只读保护、快照和使用情况选项——都是其 connections.json 条目中的字段;请参阅连接字段。

构建

# Set JDK 21+ explicitly if it is not your default JDK:
export JAVA_HOME="$HOME/.jdks/jdk-21.0.6"

./gradlew build

结果:build/libs/jdbc-mcp-server.jar(包含 PostgreSQL、Oracle、SQL Server、Firebird 和 SQLite 驱动程序)。

技术栈

  • Java 21、Spring Boot 4.0、Spring AI MCP 2.0.1(stdio 传输)
  • 通过 Spring Boot starter-jdbc 使用 HikariCP
  • PostgreSQL JDBC 42.7.4
  • Oracle JDBC ojdbc11 23.6.0.24.10
  • Microsoft SQL Server JDBC 12.8.1
  • Firebird JDBC(Jaybird)6.0.6
  • SQLite 3.51.3(sqlite-jdbc):用于保存使用情况索引和持久化结构快照的 WAL 目录(<catalog>.db),以及用于 SQLite 连接的驱动程序
  • 使用版本目录的 Gradle 9.3.1

故障排除

  • “Cannot find a Java installation ... matching languageVersion=21”——安装 JDK 21 或更高版本,并设置 JAVA_HOME。无法在没有互联网连接的情况下通过 Gradle 工具链下载。
  • 连接被拒绝 / ORA-01017 / FATAL / SQL Server 登录失败——检查 connections.json 中连接的 url、username 和 password。对于 PostgreSQL,使用 psql 测试 URL;对于 Oracle,使用 sqlplus user/password@...;对于 SQL Server,使用 sqlcmd -S host,1433 -d database -U user -P password 测试。
  • {"kind":"rejected","error":"Only SELECT / WITH / EXPLAIN statements are allowed"}——保护机制已生效。任何写操作都会出现此情况,属于预期行为。如果查询确实是只读的,例如通过 SELECT func(...) 调用只读函数,则可以通过。对于完全非平凡的情况,可以在该连接上设置 "readonlyGuard": "off" 来禁用保护机制。
  • Oracle 写入操作已到达数据库——正常情况下,保护机制应先拦截该操作。如果 readonlyGuard 为 off,请使用只读 Oracle 用户;对于 Oracle,JDBC setReadOnly(true) 只是尽力而为的提示。
  • Oracle 的 describeTable / listTables 结果为空——Oracle 会将对象名称存储为大写。请传入 CUSTOMERS,而不是 customers。
  • 通用 JDBC:“No driver in ... accepts the URL”——driverPath 中的 jar 未注册可处理该 URL 前缀的驱动程序。请检查 URL,或使用 driverClass 指定类名。
  • 通用 JDBC:kind: "unsupported"——该工具需要 JDBC 无法以可移植方式提供的功能(执行计划、视图源代码、序列)。请参阅通用 JDBC,了解可用功能。
  • Firebird:describeTable 返回 not_found,或出现 argument 错误“Firebird has no schemas”——Firebird 会将未加引号的名称存储为大写,且没有 schema:请传入 CUSTOMERS 并省略 schema(或传入 PUBLIC)。
  • SQLite:“unable to open database file”——URL 中的路径不存在(只读打开不会创建文件)或不可读。请使用绝对路径;在 Windows 上可以使用正斜杠:jdbc:sqlite:C:/data/app.db。
  • Firebird:“unsupported on-disk structure”——服务器版本与文件的 ODS 不匹配(Firebird 3 仅能读取 ODS 12,Firebird 4/5 可读取 ODS 13)。请使用匹配的 Firebird 版本提供该文件,或使用 gbak 备份文件并在较新版本中还原。
  • SQL Server 证书错误——显式设置 JDBC URL 加密选项,例如使用受信任的证书并设置 encrypt=true;trustServerCertificate=false,或仅在本地/开发环境中设置 trustServerCertificate=true。
  • SQL Server 不支持 unusedIndexes——该工具有意避免使用 sys.dm_db_index_usage_stats,因为通常需要提升状态视图权限。对于低权限的 SQL Server 审计,请使用 indexStats、fkIndexCoverage 和 redundantIndexes。
  • MCP 客户端提示服务启动失败——在终端运行 java -jar jdbc-mcp-server.jar < /dev/null;格式错误的 connections.json、无效的连接名称或未设置的 ${VAR} 都会在此处报告。请参阅检查配置。
  • connections.json 中的设置不起作用——未知键会被忽略,且不会发出警告,因此请对照连接字段检查拼写。该文件仅在启动时读取:编辑后请重启或重新连接服务。
  • 连接在 listConnections 中显示 configError——该条目不可用(URL 不受支持且未设置 driverPath、dialect 未知、缺少驱动 jar);其他连接仍可正常工作。配置错误列出了所有消息。

许可证

本项目采用 Apache License, Version 2.0 许可。请参阅 LICENSE。

运行时依赖和测试依赖由其各自所有者授权。请参阅 THIRD_PARTY_NOTICES.md,尤其是在分发包含打包 JDBC 驱动程序的构建版 fat jar 时。

评论

支持 Markdown

第一次接触 MCP?

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

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