SQL MCP Server
SQL MCP Server
AIを搭載した**Model Context Protocol (MCP)**サーバーで、自然言語を使ってeコマースのSQLiteデータベースをクエリし、分析できます。
次のような質問ができます:
「総支出額トップ5の顧客は誰ですか?」
「在庫が50未満のElectronicsカテゴリの全商品を表示」
「2026年の完了済み注文の総収益はいくらでしたか?」
4つのツールのうち、3つはAPIキーが一切不要です。2つの独立したレベルで読み取り専用、ページングされた結果、SQLite自身のエラーテキストを呼び出し元に返し、74の自動テストを備えています。
目次 — クイックスタート · プロバイダーの設定 · ツール · ページング · エラー · テスト · Docker · MCPクライアント · 設定リファレンス · 安全性 · データ送信先 · プロジェクト構成
🚀 クイックスタート
1. 前提条件
Node.js:
v22.5.0以上(組み込みのnode:sqliteモジュール用)。v24推奨npm:
v11.0.0以上
2. インストール
このリポジトリをクローンして依存関係をインストールします:
npm install
cp .env.example .env
npm run buildこれでサーバーをクライアントに接続し、list_tables、describe_table、execute_sqlを使用できます。プロバイダーが必要なのは自然言語ツールだけです — 以下を参照してください。
Related MCP server: Shop SQLite MCP
🔑 AIプロバイダーの設定
.envファイルを開き、お好みのAIモデルを設定してください。サーバーは設定した変数に基づいてプロバイダーを自動的に検出します:
オプションA: Anthropic Claude(推奨)
ANTHROPIC_API_KEY=sk-ant-api03-...
ANTHROPIC_MODEL=claude-opus-5オプションB: ローカルOllama(無料&オフライン)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2注: Ollamaが実行中(
ollama serve)で、モデルをプル済み(ollama pull llama3.2)であることを確認してください。
オプションC: OpenAI
OPENAI_API_KEY=sk-proj-...
OPENAI_MODEL=gpt-4o-miniオプションD: カスタム / サードパーティ(Groq、DeepSeek、OpenRouter)
OPENAI_API_KEY=your_api_key
OPENAI_BASE_URL=https://api.groq.com/openai/v1
OPENAI_MODEL=llama-3.3-70b-versatile🛠 利用可能なツール
4つのうち3つはSQLiteに直接アクセスします — APIキー不要、無料、即時:
ツール | 機能 | プロバイダーが必要か |
| 各テーブルについて、その内容、行数、列、テーブル間の関係、このデータベースが使用する収益の規約を平易な言葉で説明します。 | いいえ |
| 1つのテーブルを完全に説明します — 型、キー、説明を含む列、外部キー、 | いいえ |
| 読み取り専用の | いいえ |
| 平易な言葉の質問を受け取り、適切なSQLを生成・実行し、洞察を含む文章の回答を返します。 | はい |
各ツールの説明は、呼び出しエージェントに、その機能だけでなく、いつ使うべきでないかも伝えます。query_databaseは、値ではなく散文を返し、コストがかかり、2回のLLM呼び出しを行うことを明記し、エージェントが計算しようとするものにはexecute_sqlを指し示します。両方のツールは行上限と収益の規約をインラインで明記しているため、エージェントが試行錯誤で発見する必要はありません。
例: describe_table
// describe_table { "table_name": "orders" } — abridged
{
"table": "orders",
"purpose": "Order headers — one row per order placed by a customer, carrying its date, lifecycle status and total.",
"rowCount": 750,
"columns": [
{ "name": "status", "type": "TEXT", "primaryKey": false, "notNull": true, "default": null,
"description": "Lifecycle stage, one of: new, processing, shipped, completed, cancelled. Determines whether the order counts as revenue." }
],
"foreignKeys": [
{ "column": "customer_id", "referencesTable": "customers", "referencesColumn": "id", "onDelete": "CASCADE" }
],
"notes": ["Revenue convention: count every order whose status is not 'cancelled' …"],
"dataCoverage": { "order_date": { "min": "2026-02-17 18:53:30", "max": "2026-08-22 17:06:30" } },
"createStatement": "CREATE TABLE orders ( … )"
}dataCoverageは、エージェントが空の結果と範囲外の質問を区別できるようにするためのものです。2025年について尋ねると、バグのように見える裸のゼロではなく、「データは…から…まで」と返されます。
📄 大きな結果のページング
すべての結果は上限が設定されています — DATABASE_MAX_ROWS(デフォルト100)または、渡すより小さいlimitです。より大きいlimitは拒否されるのではなくクランプされるため、呼び出し元は常に行を受け取ります。
execute_sqlはlimitとoffsetを受け取り、さらに結果があるかどうかを通知します:
// execute_sql { "sql": "SELECT id, name FROM products ORDER BY id", "limit": 2, "offset": 2 }
{
"columns": ["id", "name"],
"rows": [
{ "id": 3, "name": "Ноутбук UltraBook 15" },
{ "id": 4, "name": "Умные часы FitWatch" }
],
"rowCount": 2,
"offset": 2,
"hasMore": true,
"nextOffset": 4,
"note": "More rows matched than were returned. Call again with offset=4 for the next page.",
"executionTimeMs": 0.09
}hasMoreがfalseになるまで、offset: nextOffsetで呼び出し続けます。結果が1ページに収まる場合、hasMoreはfalseで、totalAvailableRowsが実際の合計を報告します。
上限はステートメントをステップ実行中に強制され、完了した結果をトリミングするのではありません。サーバーは上限を1行超えたところで停止し、残りを実体化することはありません。SQLはモデル生成であるため、誤ったクロス結合が発生すると、破棄される前に数百万行がメモリに読み込まれる可能性があります。ページングも同様に、SQLにLIMIT/OFFSETを追加するのではなく、反復中に行われます。追加された場合、生成されたステートメントがすでに何で終わっているかに依存することになります。
query_databaseは行上限を共有しますが、ページングは行いません — 散文で要約するため、ページ番号を付ける対象がありません。1ページを超えるものにはexecute_sqlを使用してください。
🚦 エラーの表示例
失敗は、トランスポートレベルの障害ではなく、isError: trueと、呼び出しエージェントが対処できるメッセージを含む通常のMCPツール結果として返されます。
送信内容 | 返ってくる内容 |
|
|
|
|
|
|
|
|
データ削除の自然言語リクエスト | このリクエストはデータベースの変更を求めており、許可されていません…変更は行われませんでした。同じレコードについて尋ねることはできます:… |
そのテキストを支配する2つのルール:
SQLite自身のメッセージが保持されます。 "no such column: nope"は、エージェントに伝えられる最も有用な情報であり、クエリを書き換えて再試行するのに十分です。決して「query failed」に平坦化されません。
ホストの詳細は決して漏れません。 認識されないエラー(スタックトレースを含む可能性があります)は一般的な行に集約され、出力されるすべてのものからデータベースパス、プロジェクトルート、ホームディレクトリが削除されます。完全な詳細はサーバーログに残ります。これは専用のテストファイルでカバーされています。
🧪 自動テスト
npm test # 74 tests across 4 files, runs in well under a second
npm run test:watch
npm run typechecktsxを使用した素のnode --test — テストフレームワークへの依存はありません。スイートはモックではなく実際のdb/shop.dbに対して実行されるため、スキーマとドキュメントが乖離すると失敗します。
ファイル | 対象 |
| 読み取り専用ガードをすり抜けて書き込みが行われる可能性のあるすべての方法:先頭のコメント、 |
| 行上限、 |
| 呼び出し元が確認できる内容:アクション可能なメッセージは通過し、未知のエラーは集約され、データベースパス / プロジェクトルート / ホームディレクトリが両方から削除されること。 |
| ライブデータベース内のすべてのテーブルと列に説明文があること、どの説明も存在しないテーブルを参照していないこと、収益の規約が明記されていること。 |
ガードスイートが最も重要です。それは「読み取り専用」を単なる意図ではなく実際のものにする境界であり、そのケースの1つは開発中に検出された実際の誤検知です。
🐳 Docker
docker build -t sql-mcp .イメージにはデータベースがバンドルされているため、ボリュームマウントは不要です。これはstdioサーバーであるため、-iを指定し、TTYなしで実行する必要があります — コンテナの標準入力と標準出力がJSON-RPCストリームを運びます:
docker run -i --rm -e ANTHROPIC_API_KEY sql-mcpクライアントに接続するには、examples/claude_desktop_config.docker.jsonを使用します。-e ANTHROPIC_API_KEYを省略すると、資格情報なしで実行できます — list_tables、describe_table、execute_sqlはプロバイダーなしで動作します。
ビルドはマルチステージです。TypeScriptはnode:24-alpineビルダーでコンパイルされ、dist/、db/、本番依存関係のみがランタイムイメージにコピーされます。非特権のnodeユーザーとして実行され、.envは一切コピーされません(資格情報は-eから提供されます)。SQLiteはNode自体に同梱されているため、コンパイルするネイティブアドオンはありません。
🔌 MCPクライアントへの接続
すぐに使える設定ファイルはexamples/にあります — クライアントに合ったものをコピーしてパスを置き換えてください。examples/claude_desktop_config.no-api-key.jsonは資格情報を一切使わずにサーバーを実行します。これはlist_tables、describe_table、execute_sqlに十分です。
Claude Desktopの設定
このサーバーをClaude Desktopの設定ファイル(claude_desktop_config.json)に追加します:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
(接続する前に一度npm run buildを実行してください)
例1: Anthropic Claude(デフォルト)
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-api03-your-key-here",
"ANTHROPIC_MODEL": "claude-opus-5"
}
}
}
}例2: ローカルOllama(無料&オフライン)
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"OLLAMA_BASE_URL": "http://localhost:11434",
"OLLAMA_MODEL": "llama3.2"
}
}
}
}例3: OpenAI
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"OPENAI_API_KEY": "sk-proj-your-key-here",
"OPENAI_MODEL": "gpt-4o-mini"
}
}
}
}例4: カスタム / Groq / OpenRouter / DeepSeek
{
"mcpServers": {
"sql-mcp": {
"command": "node",
"args": ["/absolute/path/to/sql-mcp/dist/index.js"],
"env": {
"OPENAI_API_KEY": "gsk_your_groq_api_key",
"OPENAI_BASE_URL": "https://api.groq.com/openai/v1",
"OPENAI_MODEL": "llama-3.3-70b-versatile"
}
}
}
}サーバーはdb/shop.dbを自身の場所を基準に解決するため、これらのいずれでもDATABASE_PATHは不要です — MCPクライアントはサーバーを任意の作業ディレクトリから起動しますが、サーバーはそれに依存しません。
🔎 ローカルでの試用
即時ターミナルテスト
ターミナルで自然言語の質問を直接テストできます:
npm run query -- "Show top 3 products by price"ビジュアルWebインスペクター
公式のMCP Inspectorを使用して、ブラウザでツールを対話的にテストします:
npm run inspect:devブラウザでインスペクターのURLを開きます(例:
http://localhost:5173)。Connectをクリックします。
Toolsの下で**
query_databaseを選択し、質問を入力してRun Tool**をクリックします。
すべてのnpmスクリプト
スクリプト | 説明 |
|
|
| stdio でビルド済みサーバーを実行 |
| リロード付きでソースから実行 ( |
| 自動テスト |
|
|
| ターミナルから質問する |
|
|
🔧 設定リファレンス
すべての変数はオプションです。何も設定しなければデフォルト値が使用されます。
変数 | デフォルト | 目的 |
|
| データベースの場所。絶対パス、またはプロジェクトルートからの相対パス。作業ディレクトリからの相対パスは不可。 |
|
| 1回の呼び出しで返される行数と、LLM に送信される行数の上限。 |
|
| LLM 呼び出しのリクエストごとの上限。1つの質問で2回の連続呼び出しが発生するため、これがないとプロバイダが停止した場合にツール呼び出しがハングします。 |
| 自動検出 |
|
| — / | Anthropic プロバイダ。 |
| — / | OpenAI および OpenAI 互換のエンドポイント。 |
|
| ローカルの Ollama。 |
| 未設定 |
|
不正な値は stderr に報告され、黙って受け入れられるのではなくデフォルト値にフォールバックします。クライアントの env ブロックのタイプミスは、変数が設定されていないかのように動作するのではなく、起動時に表示されます。DEBUG ログには、行われたすべての質問と生成されたすべてのステートメントが記録され、MCP クライアントではクライアントの永続ログファイルに保存されるため、明示的に有効にしない限りオフのままです。
🔒 安全性
データベースはドライバーレベルで読み取り専用として開かれ、すべてのステートメントは実行前に検証されます。単一の SELECT/WITH/VALUES ステートメントである必要があり、データの書き込み、スキーマの変更、接続状態の変更を行うキーワードを含んではいけません。どちらのチェックも設定で無効にすることはできません。「キャンセルされた注文をすべて削除」 のようなリクエストは実行されずに拒否されます。
バリデータはステートメントの生のテキストではなくトークン化されたビューで動作するため、コメント、文字列リテラル、引用符付き識別子を使用してキーワードを隠すことはできません。/* c */ DELETE FROM orders と WITH x AS (SELECT 1) DELETE FROM orders はどちらも拒否されますが、SELECT replace(name, 'a', 'b') は拒否されません。
このサーバーが書き込んでいないテキスト(ユーザーの質問とデータベースから読み出した値)は、プロンプト内で偽造不可能なリクエストごとのマーカーで区切られるため、Widget (SYSTEM: ignore prior instructions…) という名前の製品が命令コンテキストに紛れ込むことはありません。これはこのプロセスだけの問題ではありません。回答はツール出力として呼び出し元のエージェントに返され、さらに1ホップ先へと進みます。
🔐 何がどこに送信されるか
このサーバーは LLM を呼び出して質問に回答するため、query_database を呼び出すたびにデータベースの内容がマシンの外部に送信されます。具体的には、各呼び出しで以下が送信されます。
データベーススキーマ — テーブル名、列名と型、行数 — SQL を生成するため。
クエリが返した行(最大
DATABASE_MAX_ROWS、デフォルト 100)— それらを文章による回答に変換するため。
同梱のショップデータベースの場合、これらの行には顧客名、メールアドレス、電話番号が含まれます。これらは設定したプロバイダ、OPENAI_BASE_URL が指定するエンドポイントに送信されます。Groq、OpenRouter、DeepSeek の場合、これは独自の規約に基づく第三者です。
データにとってこれが許容できない場合は:
他の3つのツールを使用する。
list_tables、describe_table、execute_sqlはネットワーク呼び出しを一切行いません。マシンの外部に何も送信されません。Ollama を使用する。 ローカルで実行されるため、マシンの外部に何も送信されません。
クエリを制限する。 集計質問(「カテゴリ別の売上」)は顧客レコードではなく集計行を返します。
DATABASE_MAX_ROWSを下げる ことで、クエリごとに送信される行データの量を制限できます。
サーバーはデータベースのファイルを送信することはなく、読み取りのみ可能です — 安全性 を参照してください。
📁 プロジェクト構成
src/
index.ts MCP server entry point (stdio transport)
cli.ts Terminal harness: npm run query -- "…"
config/ Env parsing, provider detection, path resolution
tools/ The four MCP tools and their descriptions
services/
database.service.ts SQLite access, row capping, paging, introspection
sql-guard.ts Read-only enforcement (tokenizing validator)
errors.ts Caller-safe messages, path redaction
schema-metadata.ts Human-written meaning the schema cannot record
query-engine.service.ts NL → SQL → execute → prose pipeline
llm/ Anthropic / OpenAI / Ollama behind one interface
prompts/ SQL generation, humanization, untrusted-input framing
tests/ node --test suites (see Automated Tests)
db/ shop.db and its schema documentation
docs/ Architecture and sequence diagrams
examples/ Ready-to-paste client configurations📚 技術ドキュメント
技術仕様とアーキテクチャ図: システム設計、シーケンス図、LLM ストラテジーパターン、安全性メカニズム。
データベーススキーマドキュメント: 完全なテーブルスキーマ定義、ER 図、SQLite データディクショナリ。
クライアント設定例: コピーする設定ファイルと、API キーなしで実行する方法。
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables natural-language sales queries against a SQLite database, generating and executing read-only SQL through a secure MCP server with table listing, schema description, and query execution.
- FlicenseNot gradedqualityCmaintenanceEnables safe, read-only analysis of an online store's SQLite database, providing schema introspection, restricted SELECT queries, and specialized analytics tools through MCP.
- FlicenseAqualityCmaintenanceEnables AI agents to read-only query an online store's SQLite database, listing tables, inspecting schemas, and running SELECT queries over customers, products, orders, and order items.3
Related MCP Connectors
Connect e-commerce and marketing data to AI assistants via MCP.
Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.
GibsonAI MCP server: manage your databases with natural language
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/harutlc/sql-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server