Skip to main content
Glama
harutlc

SQL MCP Server

by harutlc

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_tablesdescribe_tableexecute_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キー不要、無料、即時

ツール

機能

プロバイダーが必要か

list_tables

各テーブルについて、その内容、行数、列、テーブル間の関係、このデータベースが使用する収益の規約を平易な言葉で説明します。

いいえ

describe_table

1つのテーブルを完全に説明します — 型、キー、説明を含む列、外部キー、CREATE TABLE文、注意点、日付列が実際にカバーする範囲。

いいえ

execute_sql

読み取り専用のSELECTを実行し、構造化されたJSON行と列名を返します。limit / offsetページングをサポートします。自分で分析を進めたい場合に使用するツールです。

いいえ

query_database

平易な言葉の質問を受け取り、適切な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_sqllimitoffsetを受け取り、さらに結果があるかどうかを通知します:

// 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
}

hasMorefalseになるまで、offset: nextOffsetで呼び出し続けます。結果が1ページに収まる場合、hasMorefalseで、totalAvailableRowsが実際の合計を報告します。

上限はステートメントをステップ実行中に強制され、完了した結果をトリミングするのではありません。サーバーは上限を1行超えたところで停止し、残りを実体化することはありません。SQLはモデル生成であるため、誤ったクロス結合が発生すると、破棄される前に数百万行がメモリに読み込まれる可能性があります。ページングも同様に、SQLにLIMIT/OFFSETを追加するのではなく、反復中に行われます。追加された場合、生成されたステートメントがすでに何で終わっているかに依存することになります。

query_databaseは行上限を共有しますが、ページングは行いません — 散文で要約するため、ページ番号を付ける対象がありません。1ページを超えるものにはexecute_sqlを使用してください。


🚦 エラーの表示例

失敗は、トランスポートレベルの障害ではなく、isError: trueと、呼び出しエージェントが対処できるメッセージを含む通常のMCPツール結果として返されます。

送信内容

返ってくる内容

SELECT nope FROM products

Query execution failed: no such column: nope

DELETE FROM orders

Only read-only queries are permitted. A statement must begin with SELECT, WITH or VALUES, but this one begins with "DELETE".

SELECT 1; SELECT 2

Only a single SQL statement may be executed. Multiple statements were provided.

describe_table {"table_name": "custmers"}

No table named "custmers". Available tables: customers, order_items, orders, products.

データ削除の自然言語リクエスト

このリクエストはデータベースの変更を求めており、許可されていません…変更は行われませんでした。同じレコードについて尋ねることはできます:…

そのテキストを支配する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 typecheck

tsxを使用した素のnode --test — テストフレームワークへの依存はありません。スイートはモックではなく実際のdb/shop.dbに対して実行されるため、スキーマとドキュメントが乖離すると失敗します。

ファイル

対象

tests/sql-guard.test.ts

読み取り専用ガードをすり抜けて書き込みが行われる可能性のあるすべての方法:先頭のコメント、WITH x AS (…) DELETE、積み重ねられたステートメント、マークダウンフェンスで囲まれたDML。さらにその逆 — replace()、文字列リテラル内のキーワード、キーワードにちなんで名付けられた引用識別子が拒否されないこと。

tests/database.test.ts

行上限、offsetページング、末尾を超えるオフセット、実体化してはならない暴走クロス結合、空の結果での列名、拒否された書き込みがデータベースを変更しないこと、SQLiteのメッセージが保持されること。

tests/errors.test.ts

呼び出し元が確認できる内容:アクション可能なメッセージは通過し、未知のエラーは集約され、データベースパス / プロジェクトルート / ホームディレクトリが両方から削除されること。

tests/schema-metadata.test.ts

ライブデータベース内のすべてのテーブルと列に説明文があること、どの説明も存在しないテーブルを参照していないこと、収益の規約が明記されていること。

ガードスイートが最も重要です。それは「読み取り専用」を単なる意図ではなく実際のものにする境界であり、そのケースの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_tablesdescribe_tableexecute_sqlはプロバイダーなしで動作します。

ビルドはマルチステージです。TypeScriptはnode:24-alpineビルダーでコンパイルされ、dist/db/、本番依存関係のみがランタイムイメージにコピーされます。非特権のnodeユーザーとして実行され、.envは一切コピーされません(資格情報は-eから提供されます)。SQLiteはNode自体に同梱されているため、コンパイルするネイティブアドオンはありません。


🔌 MCPクライアントへの接続

すぐに使える設定ファイルはexamples/にあります — クライアントに合ったものをコピーしてパスを置き換えてください。examples/claude_desktop_config.no-api-key.json資格情報を一切使わずにサーバーを実行します。これはlist_tablesdescribe_tableexecute_sqlに十分です。

Claude Desktopの設定

このサーバーをClaude Desktopの設定ファイル(claude_desktop_config.json)に追加します:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %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
  1. ブラウザでインスペクターのURLを開きます(例:http://localhost:5173)。

  2. Connectをクリックします。

  3. Toolsの下で**query_databaseを選択し、質問を入力してRun Tool**をクリックします。

すべてのnpmスクリプト

スクリプト

説明

npm run build / npm run clean

dist/ にコンパイル · 削除

npm start

stdio でビルド済みサーバーを実行

npm run dev

リロード付きでソースから実行 (tsx watch)

npm test / npm run test:watch

自動テスト

npm run typecheck

tsc --noEmit

npm run query -- "…"

ターミナルから質問する

npm run inspect / npm run inspect:dev

dist/ に対する MCP Inspector · ソースに対する


🔧 設定リファレンス

すべての変数はオプションです。何も設定しなければデフォルト値が使用されます。

変数

デフォルト

目的

DATABASE_PATH

db/shop.db

データベースの場所。絶対パス、またはプロジェクトルートからの相対パス。作業ディレクトリからの相対パスは不可。

DATABASE_MAX_ROWS

100

1回の呼び出しで返される行数と、LLM に送信される行数の上限。execute_sqllimit はこの値を下げることしかできません。

LLM_TIMEOUT_MS

60000

LLM 呼び出しのリクエストごとの上限。1つの質問で2回の連続呼び出しが発生するため、これがないとプロバイダが停止した場合にツール呼び出しがハングします。

LLM_PROVIDER

自動検出

anthropic | ollama | openai | custom。通常は設定したキーから推測されます。

ANTHROPIC_API_KEY / ANTHROPIC_MODEL

— / claude-opus-5

Anthropic プロバイダ。

OPENAI_API_KEY / OPENAI_MODEL / OPENAI_BASE_URL

— / gpt-4o-mini / OpenAI

OpenAI および OpenAI 互換のエンドポイント。

OLLAMA_BASE_URL / OLLAMA_MODEL

http://localhost:11434 / llama3.2

ローカルの Ollama。

DEBUG

未設定

sql-mcp:*、または単一の名前空間: serverquery-enginedatabasellmtools

不正な値は stderr に報告され、黙って受け入れられるのではなくデフォルト値にフォールバックします。クライアントの env ブロックのタイプミスは、変数が設定されていないかのように動作するのではなく、起動時に表示されます。DEBUG ログには、行われたすべての質問と生成されたすべてのステートメントが記録され、MCP クライアントではクライアントの永続ログファイルに保存されるため、明示的に有効にしない限りオフのままです。


🔒 安全性

データベースはドライバーレベルで読み取り専用として開かれ、すべてのステートメントは実行前に検証されます。単一の SELECT/WITH/VALUES ステートメントである必要があり、データの書き込み、スキーマの変更、接続状態の変更を行うキーワードを含んではいけません。どちらのチェックも設定で無効にすることはできません。「キャンセルされた注文をすべて削除」 のようなリクエストは実行されずに拒否されます。

バリデータはステートメントの生のテキストではなくトークン化されたビューで動作するため、コメント、文字列リテラル、引用符付き識別子を使用してキーワードを隠すことはできません。/* c */ DELETE FROM ordersWITH x AS (SELECT 1) DELETE FROM orders はどちらも拒否されますが、SELECT replace(name, 'a', 'b') は拒否されません。

このサーバーが書き込んでいないテキスト(ユーザーの質問とデータベースから読み出した値)は、プロンプト内で偽造不可能なリクエストごとのマーカーで区切られるため、Widget (SYSTEM: ignore prior instructions…) という名前の製品が命令コンテキストに紛れ込むことはありません。これはこのプロセスだけの問題ではありません。回答はツール出力として呼び出し元のエージェントに返され、さらに1ホップ先へと進みます。


🔐 何がどこに送信されるか

このサーバーは LLM を呼び出して質問に回答するため、query_database を呼び出すたびにデータベースの内容がマシンの外部に送信されます。具体的には、各呼び出しで以下が送信されます。

  1. データベーススキーマ — テーブル名、列名と型、行数 — SQL を生成するため。

  2. クエリが返した行(最大 DATABASE_MAX_ROWS、デフォルト 100)— それらを文章による回答に変換するため。

同梱のショップデータベースの場合、これらの行には顧客名、メールアドレス、電話番号が含まれます。これらは設定したプロバイダ、OPENAI_BASE_URL が指定するエンドポイントに送信されます。Groq、OpenRouter、DeepSeek の場合、これは独自の規約に基づく第三者です。

データにとってこれが許容できない場合は:

  • 他の3つのツールを使用する。 list_tablesdescribe_tableexecute_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

📚 技術ドキュメント

Install Server
F
license - not found
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables 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.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables safe, read-only analysis of an online store's SQLite database, providing schema introspection, restricted SELECT queries, and specialized analytics tools through MCP.
  • F
    license
    A
    quality
    C
    maintenance
    Enables read-only interaction with an online store's SQLite database over MCP stdio, including table listing, schema inspection, safe read-only SQL execution, and sales analytics. It rejects mutating SQL operations to keep data intact.
    4
  • F
    license
    A
    quality
    C
    maintenance
    Enables 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

View all related MCP servers

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

View all MCP Connectors

Latest Blog Posts

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