JDBC MCP Server について
JDBC MCP Serverは、JDBC経由でAIエージェントにリレーショナルデータベースの読み取り専用アクセスを提供します。スキーマ探索、SQL実行、実行計画やインデックス分析に加え、複数接続の情報をローカルカタログに保存します。
主な機能
- 01読み取り専用SELECTとスキーマ確認
- 02実行計画、統計、インデックス分析
- 035種類のデータベースエンジンに標準対応
- 04一つのサーバーで複数接続
- 05スキーマとクエリの永続カタログ
- 06ツールグループごとの有効化設定
活用シーン
- 01不慣れなデータベースのスキーマを調査
- 02データベースのレコードを使って質問に回答
- 03遅いクエリを調査・改善
- 04スキーマとインデックスの利用状況を監査
MCP 対応
stdioでMCPサーバーとして動作し、設定可能なグループに分かれた49個のツールと、任意のリソースを公開します。各ツール呼び出しでは、設定済みのデータベース接続を指定します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
docker run -i --rm -e JDBC_MCP_RESOURCES_ENABLED ghcr.io/igorolv/jdbc-mcp-server:0.2.0JDBC_MCP_RESOURCES_ENABLEDAlso expose catalog-qualified MCP resources for table and column metadataローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ghcr.io/igorolv/jdbc-mcp-server:0.2.0stdioツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
JDBC MCP Server
JDBC 経由でリレーショナルデータベースへの読み取り専用アクセスを提供する MCP サーバー(stdio)です。スキーマメタデータ、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)に加え、エンジンが対応している場合はセッション、トランザクション、またはファイル単位の読み取り専用モードを使用します。詳細は読み取り専用保護をご覧ください。 - 接続: 任意の数のデータベースを 1 つの
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 の設定例があります。
典型的なシナリオ
エージェントが使用するツールを自分で選びます。以下は、通常たどるツールの連鎖です。各ツールの説明は MCP Tools にあります。
| シナリオ | リクエストの例 | ツール |
|---|---|---|
| データに関する質問に答える | 「先月、各地域から出荷された注文数はいくつですか?」 | 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)に、
データベースごとに 1 つのエントリを接続名をキーとして記述します。
{
"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 には、ドライバー jar のdriverPathが必要で、 汎用 JDBC として提供されます。descriptionはlistConnectionsが返すため、エージェントは意味に基づいてデータベースを選べます。接続先と制限事項(「PRODUCTION — クエリは小さく保つ」など)を記述してください。archiveはローカルの Firebird ファイルをプロセス内で開きます。nativeLibraryPathには、エンジンおよびプラグインとともにlibfbclient.so/fbclient.dllが置かれているディレクトリを指定します。ファイルのコピーを指定してください。詳しくはFirebirdをご覧ください。- 読み取り専用のデータベースユーザーを使用してください。これは、このサーバーに依存しない唯一の保護策です。ファイルは所有者のみが読み取り可能な状態にしてください。
各フィールド、命名規則、${VAR} シークレット、1 つのサービスに対する複数の接続先については、
docs/connections.mdをご覧ください。
3. MCP クライアントにサーバーを登録する — クライアント設定にデータベース設定を含める必要はありません。
{
"command": "java",
"args": ["-jar", "<absolute-path>/jdbc-mcp-server.jar"],
"env": {}
}
Claude Code と Codex CLI では、コマンドを 1 つ実行するだけです。
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. 試してみる。 エージェントに普通の言葉で質問します。
- 「どのデータベースに接続できますか?」 —
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 |
+--------------------------------------------------------------------------------+
- 1つのプロセスで複数のデータベースを扱います。 クライアントはサーバーを子プロセスとして起動し、stdio 経由で通信します。データベースの設定は
connections.jsonから読み込まれます。接続のプール、ローカルカタログ、サービスは、ツール呼び出しでその接続が初めて指定されたときにのみ作成されます。そのため、停止中または設定に誤りがあるデータベースが影響するのは、そのデータベースに対して行われる呼び出しだけです。 - SQL の実行経路。 すべてのステートメントは、まず読み取り専用ガードを通過し、その後、接続ごとの行数上限とタイムアウトを設定した読み取り専用 JDBC 接続で実行されます。エンジンレベルの保護については、読み取り専用保護をご覧ください。
- 方言。 各エンジンには、メタデータクエリ、実行計画、統計情報の独自の実装があります。それ以外のデータベースは、
DatabaseMetaDataと移植性のある SQL を使った汎用モードで処理されます。詳しくは対応データベースをご覧ください。 - ローカルカタログ。 構造メタデータは、接続ごとに有効期限のない SQLite ファイルへ保存されます。
describeTable、スキーマコンテキストツール、searchObjectsは、カタログに含まれるスキーマを読み込み、含まれない場合はライブデータベースにフォールバックします。同じファイルには使用インデックスも保存されます。ライブ統計情報、サンプル、実行計画はキャッシュされません。詳しくは永続的な構造スナップショットと使用状況カタログをご覧ください。 - 実行モデル。 1つの stdio セッション上のツール呼び出しは順次実行されます。Spring AI 2.0.1 が使用する MCP Java SDK 2.0.0 では、複数の並行実行ツールが同時に完了すると応答が失われることがあるため、SDK で修正されるまでサーバーは
immediateExecution(true)を維持します。クライアントのnotifications/cancelledは JDBC のStatement.cancel()に伝播されません。実行中の SQL ステートメントに対するサーバー側の制限は、設定されたqueryTimeoutSeconds(またはツール呼び出しで指定するtimeoutSecondsによる上書き)です。
MCP ツール
49 個のツールを、目的別に以下にまとめています。
すべてのツールでは、実行対象のデータベースを指定する connection が最初の必須引数です。データベースを1つだけ提供するインストールでも同様です。listConnections で名前の一覧を取得できます。1つのサーバーで複数のデータベースを扱うをご覧ください。
ツールグループ
ツールはグループに整理されており、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 | 大量の生の計画ダンプの代わりに、LLM 向けの簡潔な計画の要約を返します。対象は、コストが最も高いノード、大規模テーブルの全件スキャン、推定誤差(プランナーの推定と実際の結果との差。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)で渡せます。LLM の自己修正に役立ちます |
inspectQuery | データベースにアクセスせずに JSqlParser で SQL を解析し、テーブル、エイリアス、CTE、選択項目、結合、述語、ORDER BY、列、パラメーター、機能、パーサーの警告を含む AST の要約を返します |
queryLint | SQL を解析し、AST にメタデータ、インデックス、FK のチェックを組み合わせます。不明なテーブルや列、SELECT *、条件のない結合、対応するインデックスのない FK、先頭のインデックス列ではない述語/ORDER BY の列など、参考情報としての警告を返します。SQL は実行されません |
resolveQueryLineage | クエリが参照する直接のオブジェクトを解決し、データベースのビュー/マテリアライズドビューを再帰的に展開して、基盤となる物理テーブルを特定します。関数/プロシージャの展開はベストエフォートです。利用可能な場合、ルーチンのソースから埋め込みの SELECT/WITH 文を抽出します。パラメーター:sql、schema、expandViews、expandRoutines、maxDepth |
ベンチマーク
クエリの実際のコストを測定するツールです。LLM が計画から推測する必要がなく、実際の処理時間(ミリ秒)やバッファーカウンターを確認できます。
| ツール | 説明 |
|---|---|
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 | 1 回の呼び出しでオブジェクトの全情報を説明します。列、主キー、一意制約、インデックス、外部キーの参照先/参照元、CHECK 制約と許容値、簡潔なトリガーメタデータが含まれます |
getTriggerDefinition | 名前を指定した 1 つのトリガーの本体を取得します。パラメーター:schema、table、trigger |
getViewDefinition | ビューの SQL 定義を取得します |
listRoutines | スキーマ内の関数、プロシージャ、パッケージを一覧表示します |
getRoutineDefinition | 関数またはプロシージャのソースコードを取得します。Oracle では、すべての ALL_SOURCE 行が順番に連結されます |
listSequences | 1 つのスキーマ内のシーケンスを一覧表示します。schema を省略すると、複数のスキーマを対象にします |
searchObjects | システム以外のテーブル、ビュー、ルーチン、シーケンス、シノニムを対象に、大文字と小文字を区別しない部分文字列検索を行います |
スキーマのコンテキスト
スキーマをすばやく把握し、SQL を作成するための高レベルツールです。各テーブルに対して
listTables -> describeTable -> sampleRows を手動で呼び出す代わりに、LLM はすぐに使える
コンテキスト(テーブル、列、リレーションシップ、制約、サンプル行)を 1 回の呼び出しで取得できます。
| ツール | 説明 |
|---|---|
tableContext | 1 つのテーブルに関するコンテキストを取得します。対象のテーブル、外部キーの参照元テーブル、オプションで子テーブルとリレーションシップのエッジが含まれます。外部キーのたどり方は、指定した深さを使用します(デフォルト 1、最大 4)。パラメーター:schema、table、depth、includeIncoming、includeStats、includeObserved |
findJoinPaths | 外部キーを介して 2 つのテーブル間の JOIN 経路を見つけます。グラフは両方向にたどられ、各エッジには joinCondition と型付きの evidence バンドルが含まれます(下記の エッジの証拠 を参照)。パラメーター:fromSchema/fromTable、toSchema/toTable、maxDepth(デフォルト/最大 4)、maxPaths(デフォルト 5、最大 25)、scanLimit(デフォルト/最大 300)、includeObserved |
schemaBrief | SQL 作成用のスキーマ全体を示すプレーンテキストのマップです。一致するすべてのテーブル/ビューについて、列数、主キー、参照元/参照先リレーションシップ数、キーらしい列、中心的/孤立したテーブル、上限付きの主要な外部キーリレーションシップを表示します。関連するテーブルが不明な場合は、まずこれを使用し、続いて詳細なコンテキストを得るために queryContext を使用します。パラメーター:schema、terms(任意の部分文字列検索)、maxTables(安全上の上限。デフォルト 2000、最大 5000) |
schemaGraph | スキーマのリレーションシップグラフのメトリクスを取得します。入次数/出次数と分類を含むノード、エッジ、中心的なテーブル、孤立したテーブル、連結成分、サイクルのヒントが含まれます。オプションで 2 つのテーブル間の最短経路も含められます |
schemaLint | スキーマのリント監査を行います。主キーの欠落、インデックスのない外部キー、外部キーの型の不一致、NULL 許容の一意制約、CHECK 制約のないステータス/型の列、孤立した *_id 列、備考の欠落、孤立したテーブル、幅の広いテーブルを検出します。checks で検査項目を設定できます |
queryContext | 検索語や明示的に指定したテーブルから、SQL 作成用のコンパクトなコンテキストを構築します。宣言されたスキーマ名/コメントに加え、利用可能な場合は使用カタログのセマンティックな証拠を使って、関連するテーブルと列を特定します。制約と許容値、選択したテーブル間のリレーションシップと JOIN 経路、オプションでサンプル行(テーブルごとに最大 3 行)を含みます |
schemaGraphDot | スキーマのリレーションシップグラフを DOT/Graphviz 形式で表します。ノードはすべての列と型を持つテーブルであり(PK と FK はインラインで示されます)、エッジには JOIN 条件が含まれます。パラメーター:schema、tables(任意のカンマ区切りフィルター) |
エッジのエビデンス
includeObserved を未設定のままにすると、ローカルの使用カタログが有効な場合、tableContext / findJoinPaths で自動的に有効になります(下記の 使用カタログ を参照)。各リレーションシップのエッジには、型付きの3層構成の 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 で提示されるのは、宣言済みの外部キーリレーションシップのみです。
エビデンスモデル
スキーマコンテキスト層では、次の3つの知識ソースを分けて保持します。
declared_schema- データベースのライブ introspection:テーブル、列、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 セル、ダッシュボードウィジェットなど)が含まれます。
ソースは2つあります。ファイルベースの使用状況は、正規の QueryUsage JSON レコードを含むディレクトリ/JSON ファイル/zip アーカイブから取得されます。データベースネイティブの使用状況は、接続先スキーマのビュー、ルーチン、トリガーから自動的に導出されます。実行時に、サーバーはこれらのレコードを解析し、抽出したテーブル/列/等価結合ペアを事実として保持する永続的な SQLite インデックスを構築します。ファイルベースのレコードは引き続き JSON ファイルを正とし、ネイティブレコードはライブメタデータから更新されます。
目的。 メタデータツールは「どのテーブルと列が存在するか」に答える一方、使用状況カタログは「アプリケーションでどのように使われているか」に答えます。「この列を参照しているレポートはどれか」「この出力フィールドにはどの業務ラベルが付いているか」といった検索をサポートし、リレーションシップのevidenceバンドルのobservedQueryレイヤーとsemanticUsageレイヤーに情報を提供します。そのため、保存済みクエリで確認された等価結合が、宣言済み外部キーと並べて表示されます(たとえば、「これらの2つの列は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に#を含めることはできません。ソースキーが重複している場合、そのインデックスの構築では最初のレコードが採用されます。
ファイルの保存場所。 デフォルトのカタログディレクトリは<data-dir>/<connection>/usage-catalogです。接続のusageCatalogPathsには、追加のディレクトリ、.jsonファイル、または.zipアーカイブをリストとして指定します。ディレクトリは*.jsonを再帰的に検索し、zipアーカイブはJSONエントリを検索します。usageCatalogEnabled: falseを設定すると、カタログが無効になります。この場合、usageCatalogStatusはcatalogEnabled: falseを返し、その他の公開使用状況ツールは、有効化方法を説明するargumentエラーを返します。
データベースネイティブの使用状況。 カタログは、デフォルトスキーマからサポート対象のデータベースオブジェクトもインデックス化します。
- ビュー/マテリアライズドビューは、
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解析パイプラインに渡します。埋め込み文が見つからない場合でも、オブジェクトは来歴レコードとして保持されます。明示的なスキーマをスキャンするには、接続のusageNativeSchemasを使用します。
永続インデックス。 サーバーは起動時に使用状況インデックスを構築しません。使用状況カタログの検索が初めて行われると、ファイルベースのレコードとデータベースネイティブのオブジェクトから、ローカルのSQLite<catalog>.dbに同期的にインデックスが構築されます。ソースファイルとデータベースオブジェクトが引き続き正本です。これらを変更した後はinvalidateUsageCatalogCacheを使用してください。インデックス化された使用状況の行がクリアされ、次回の検索時にインデックスが再構築されます。
ローカル限定の書き込み。 使用状況カタログが、検査対象のJDBCデータベースに書き込むことはありません。既存のReadOnlyGuardと接続レベルの保護は引き続き有効です。
型付きペイロード。 標準の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 | カタログで現在使用されているタグとクエリ件数です。エージェントはこれを使って、取り込み呼び出し全体で安定した語彙を再利用できます |
listKnownDomains | businessDomain の値についても同様です |
listKnownKinds | カタログで現在使用されているソース種別とクエリ件数です。エージェントが listQueries の sourceKind フィルターに指定できる値を確認するのに役立ちます |
解決。 インデックス作成時、テーブル/列の修飾子はパーサーの別名マップを使って低コストで解決され、大文字と小文字を区別しない照合のために大文字に変換されます。SQL 内で明示されたスキーマ(SCHEMA.TABLE)はそのまま保持されます。修飾されていないテーブル参照は、インデックス構築時に稼働中の JDBC スキーマを対象に解決されます。一致が 1 件の場合はスキーマが補完され、複数件の場合は ambiguous として扱われ、一致が 0 件の場合は unresolved のままになります。
カタログ管理
| ツール | 説明 |
|---|---|
rebuildCatalog | カンマ区切りの schemas(または設定済み/デフォルトの範囲)について、永続的な構造スナップショットと使用状況インデックスを再構築し、SQLite WAL をチェックポイント処理して、配布可能な <catalog>.db のパスと、構築に使用した接続を返します |
このツールが書き込むのはローカルカタログのみです。調査対象のデータベースは変更しません。
接続
| ツール | 説明 |
|---|---|
listConnections | このサーバーが提供するデータベースの一覧です。connection として渡す値である name、description、エンジンの種類、デフォルトスキーマ、ローカルカタログファイルがすでに存在するかどうか、およびこのプロセスでコネクションプールが構築済みかどうかを返します |
listConnections が読み取るのは設定とローカルファイルシステムのみです。データベース接続は開かないため、設定済みデータベースの一部が停止している場合も応答します。使い慣れていない環境では、最初に呼び出すのがおすすめです。
永続構造スナップショット
構造メタデータ(列、キー、インデックス、外部キー、ビュー、ルーチン、トリガー、シーケンス)は、ローカルの SQLite <catalog>.db ファイル(使用状況カタログと同じデータベースファイルで、<data-dir>/<catalog>/ の下にあります)に保存される永続構造スナップショットに保持されます。SQLite は WAL モードで動作するため、Codex、Claude、その他のローカルエージェントプロセスが同じカタログを同時に使用できます。これにより、tableContext、findJoinPaths、schemaLint、schemaGraph、queryContext、describeTable、searchObjects、使用状況カタログのリゾルバーによる再解決を繰り返し呼び出す際の速度が向上します。tableStats、indexStats、columnStats、sampleRows などの統計ツールはキャッシュされず、カウンターはライブです。
スナップショットは正本として扱われ(「永久にキャッシュ」)、TTL や古さの検出機能はありません。スナップショットは遅延読み込みで作成され(describeTable が読み込んだ各テーブルを保存します)、rebuildCatalog ツールを使ってスキーマ全体のデータを事前に読み込むこともできます。このツールは構造スナップショットと使用状況インデックスを、配布可能な 1 つの <catalog>.db に構築します。rebuildCatalog は戻る前に WAL をチェックポイントします。すべてのサーバープロセスを停止した状態で、<catalog>.db と隣接する <catalog>.db-wal/<catalog>.db-shm ファイルを削除すると、カタログをクリアできます。
既存の H2 <catalog>.mv.db ファイルは変換も削除もされません。SQLite の初回起動時にサーバーは新しい <catalog>.db を作成し、警告をログに記録しますが、従来のファイルはそのまま残します。新しいカタログにデータを格納するには、rebuildCatalog を実行してください。
設定:
structureSnapshotSchemas- 全体の再構築時に事前読み込みするスキーマ(空の場合 → デフォルトスキーマ)。structureSnapshotOracleColumnQueryTimeoutSeconds- 全体の再構築時に実行する、DBMS_XMLGENベースの一括列/デフォルト値クエリに対する Oracle 専用タイムアウト(デフォルトは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 が報告するのは最小値と最大値のみです。ほかのツールは、「この述語の選択性はどの程度か」「この列の値はどれほど偏っているか」という問いに答えます。これは、LLM がインデックスの選択や JOIN の書き換えを適切に行うために必要な情報です。
| ツール | 説明 |
|---|---|
columnDistribution | 列で最も頻度の高い値を上位 N 件まで、それぞれの割合とともに返します。たとえば status='OK' の行が 70% を占めるような偏りを明らかにします。この場合、status だけを対象とするインデックスは有用ではありません。パラメーター:schema、table、column、topN(デフォルトは 20、最大 1000) |
columnHistogram | P25/P50/P75/P90/P95/P99 のパーセンタイルに加え、min、max、NULL の件数を返します。SQL:2003 の WITHIN GROUP を使用します。数値型には percentile_cont、日付、タイムスタンプ、テキストを含むその他すべての型には percentile_disc を使います |
nullRatio | 1 回のスキャンで、テーブルのすべての列について NULL/非 NULL の件数を返します。列は null_ratio の降順で並べられます。sparse=true は、行の 50% 超が NULL である列を示します。このような列は部分インデックスの候補になる場合があります |
estimateSelectivity | SELECT 1 FROM t WHERE <predicate> に対して EXPLAIN を使い、クエリを実行せずに述語が返す行数を推定します。推定行数、フィルター適用前の基準行数、選択性を返します。複合インデックスで最も選択性の高い述語を先頭に配置するのに役立ちます |
joinCardinality | JOIN を実行せずに、JOIN の出力行数を推定します。プランナーによる推定値、各側の行数、selectivity_vs_cartesian を返します。INNER、LEFT、RIGHT、FULL をサポートします |
オブジェクト統計
これらのツールは、オブジェクトの規模と健全性を示す情報を LLM に提供します。これがなければ、最適化のアドバイスは推測に頼ることになります。データはシステムカタログ(pg_class、pg_stat_*、ALL_TABLES、ALL_INDEXES、DBA_SEGMENTS)から取得し、Java 側で集計されます。
| ツール | 説明 |
|---|---|
tableStats | テーブルとインデックスのサイズ(バイト単位)、推定行数、PostgreSQL でのデッドタプル数、最後に VACUUM/ANALYZE を実行した日時、シーケンシャルスキャンとインデックススキャンのカウンター。Oracle では、利用可能な場合にベストエフォートで DBA_SEGMENTS のデータも含みます |
indexStats | インデックスごとのサイズ、スキャンカウンター、列、一意/主キーのフラグ、インデックスの種類。PostgreSQL の追加情報:idx_tup_read/fetch、pg_get_indexdef。Oracle の追加情報:distinct_keys、clustering_factor、blevel、leaf_blocks、last_analyzed |
unusedIndexes | PostgreSQL(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 を設定してください。どちらの場合もツールは同じです。
使用可能な接続ごとに、1 つのリソースと 2 つのリソーステンプレートが公開されます。
| URI | 名前 | 内容 |
|---|---|---|
jdbc-mcp://catalog/<catalog>/manifest | <catalog>/manifest | データベースの種類、構造スナップショットのバージョン、ビルド時刻、対象スキーマ、および以下の 2 つのテンプレート |
jdbc-mcp://catalog/<catalog>/schemas/{schema}/tables/{table} | <catalog>/table | describeTable が返す内容:列、キー、インデックス、制約、リレーションシップ、トリガー |
jdbc-mcp://catalog/<catalog>/schemas/{schema}/tables/{table}/columns/{column} | <catalog>/column | 主キー内の位置、一意制約、インデックス、送信・受信外部キー、CHECK 制約を含む 1 つの列 |
<catalog>は接続名で、UTF-8 のパーセントエンコードが適用されます(ssj@devはssj%40devになります)。接続ごとに固定されており、テンプレート引数ではありません。読み取り時に URI から接続が特定されるため、1 つのサーバー内の接続間でも、登録済みの複数のインスタンス間でも、URI が誤ったデータベースを指すことはありません。スキーマ、テーブル、列の各セグメントはパーセントエンコードされ、大文字と小文字はそのまま保持されます。- テーブルの一覧は公開されません。
resources/listに含まれるのはマニフェストのみです。そうしないと、数千のテーブルを持つスキーマではカタログのダンプになってしまいます。クライアントはテンプレート引数に対するcompletion/completeを使って、まずschema、次に(schemaを指定して)table、続いて(両方を指定して)columnの名前を取得します。大文字と小文字を区別しない前方一致で、応答あたり最大 100 件を返し、さらに候補がある場合はhasMoreが設定されます。 - 補完候補はローカルカタログから取得され、データベースにはアクセスしません。接続にカタログがない間は候補を返さず、マニフェストのスナップショットバージョンは
0になります。rebuildCatalogで構築したカタログは、再起動なしで反映されます。テーブルと列の読み取りはどちらの状態でも動作します。describeTableと同様、スナップショットから応答し、必要に応じて稼働中のデータベースにフォールバックします。 - メタデータ。 各読み取りには、
catalog、resourceSchemaVersion、snapshotVersionを含む_metaが付与され、カタログが存在する場合はsnapshotBuiltAtも含まれます。 - エラーには MCP のエラーコードが使われます。存在しないテーブルまたは列は
-32002(リソースが見つからない。data.uriに URI が指定されます)、不正な形式の URI は-32602(無効なパラメーター)です。
読み取り専用の保護
サーバーは検査対象のデータベースに書き込むことはなく、そのために単一の仕組みに依存していません。
- JSqlParser の AST ガードは、単一の
SELECT、WITH、EXPLAINのみを許可し、それ以外はすべて拒否します。 - すべての JDBC 接続は読み取り専用であり、PostgreSQL、Firebird、SQLite はデータベース内でこれを強制します(読み取り専用セッションまたはトランザクション、
open_mode=1で開かれたファイル)。 - データベースの認証情報は
connections.jsonに保存され、MCP クライアントの設定や環境には保存されません。そのため、エージェントが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
ojdbc1123.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 ユーザーを使用してください。JDBC のsetReadOnly(true)は Oracle ではあくまでベストエフォートのヒントです。 - 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を返す、または「Firebird has no schemas」というargumentエラーが発生する - Firebird では、引用符で囲まれていない名前は大文字で保存され、スキーマはありません。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が表示される - そのエントリは使用できません(driverPathが指定されていない未サポートの URL、不明なdialect、ドライバー jar の不足など)。ほかの接続は引き続き利用できます。設定エラー には、すべてのメッセージが記載されています。
ライセンス
このプロジェクトは Apache License, Version 2.0 の下でライセンスされています。LICENSE を参照してください。
ランタイムとテストの依存関係は、それぞれの所有者によってライセンスされています。THIRD_PARTY_NOTICES.md を参照してください。特に、同梱の JDBC ドライバーを含むビルド済み fat jar を配布する場合はご確認ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。