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-db MCP Server
🔑 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 キーなしで実行する方法。
Available Tools
4 toolsdescribe_tableDescribe a Database TableA
Returns everything about one table: its purpose, every column with type, nullability, primary key and a plain-language description, its foreign keys, its CREATE TABLE statement, caveats worth knowing before querying it, and — for date columns — the range the data actually covers, so you can tell an empty result from an out-of-range question. Use it before writing SQL against a table you have not queried yet. Reads SQLite directly: no LLM call, no API key. Returns JSON.
| Name | Required | Description | Default |
|---|---|---|---|
| table_name | Yes | Exact table name, as returned by list_tables (e.g. 'orders', 'order_items'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full disclosure burden. It states execution mechanics ('Reads SQLite directly'), that no external dependency exists ('no LLM call, no API key'), and the return format ('Returns JSON'). It also explains a non-obvious behavior — returning real data coverage ranges for date columns so empty results can be distinguished from out-of-range questions. The 'describe' verb implies read-only; the description could state non-mutating explicitly but the disclosed details exceed the baseline for an annotation-less tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: deliverable list, when-to-use, and execution/return format. The content list is front-loaded ahead of the usage guidance. It is information-dense rather than wasteful, though the long enumerative first sentence could be tightened slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description bears full responsibility for explaining return content — it enumerates all major elements including the non-obvious date-range feature. One fully-documented parameter, usage routing against siblings, execution behavior, and return format are all specified. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single table_name parameter, which the schema already documents as 'Exact table name, as returned by list_tables (e.g. 'orders', 'order_items').' With full schema coverage the baseline is 3; the description adds no parameter-specific detail beyond hinting that the table must exist (it describes 'one table'). The schema does the heavy lifting, so 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb-resource pair ('Returns everything about one table') and enumerates the exact contents delivered: columns with type/nullability/PK/plain-language, foreign keys, CREATE TABLE, caveats, and date range coverage. It clearly differentiates from siblings — it describes schema rather than querying data (query_database, execute_sql) or listing tables (list_tables).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use instruction: 'Use it before writing SQL against a table you have not queried yet.' This frames it as a prerequisite step and implies the alternative is the SQL/query tools, though it does not name them explicitly or state when-not-to-use. Clear context, slightly implicit on exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
execute_sqlRun a Read-Only SQL QueryA
Runs a single read-only SQL query against the e-commerce SQLite database and returns structured rows plus column names as JSON. Use this to answer analytical questions yourself — joins, aggregates, multi-step work — and when you need the actual values rather than a written summary. Call list_tables and describe_table first if you do not know the schema.
LIMITATIONS: SELECT only. The statement must be a single SELECT (or WITH ... SELECT, or VALUES); anything that writes data, changes schema, or alters connection state is rejected, as is more than one statement per call. SQLite dialect. Results are capped at 100 rows per call — use offset to page through more, and check hasMore in the response. No LLM is involved: no API key needed, no cost, and the result is exact.
Revenue convention: count every order whose status is not 'cancelled' (i.e. new, processing, shipped and completed all count as revenue). Cancelled orders are excluded because the sale did not complete. To count only fully delivered sales instead, filter status = 'completed' and say so in the answer.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | A single read-only SQL SELECT statement in SQLite dialect. Example: "SELECT p.name, SUM(oi.quantity) AS units FROM order_items oi JOIN products p ON p.id = oi.product_id JOIN orders o ON o.id = oi.order_id WHERE o.status != 'cancelled' GROUP BY p.id ORDER BY units DESC LIMIT 5" | |
| limit | No | Maximum rows to return (default and hard ceiling: 100). Larger values are clamped. | |
| offset | No | Rows to skip before returning results. Use with `limit` to page through a large result set. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It thoroughly discloses: read-only and SELECT-only enforcement, single-statement limitation, SQLite dialect, row cap of 100 with offset/hasMore paging, no LLM involvement (no key, no cost, exact results), and the revenue convention (counting non-cancelled orders). This is exemplary transparency for a tool that executes arbitrary SQL.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than a single sentence but every section earns its place: purpose, use case, limitations, and revenue convention are separated and clearly front-loaded. It respects the reader by grouping constraints and providing a concrete example. Slightly verbose but never wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description correctly explains return format ('structured rows plus column names as JSON') and mentions hasMore. It covers all necessary operational details: single-statement rule, paging, dialect, and domain convention. For a complex SQL tool with no annotations, this is remarkably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all three parameters (sql, limit, offset). The description reinforces paging behavior ('use offset to page through more') and the revenue convention, but adds no new parameter semantics beyond what the schema provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Runs') and resource ('read-only SQL query against the e-commerce SQLite database') and specifies the output shape ('structured rows plus column names as JSON'). It clearly separates itself from sibling tools by instructing to use list_tables and describe_table first when schema is unknown, implying this tool is for querying after schema discovery.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear when-to-use guidance: 'Use this to answer analytical questions yourself' mentioning joins, aggregates, and multi-step work, and when actual values are needed rather than a written summary. It also gives a prerequisite ('Call list_tables and describe_table first if you do not know the schema') and explicit limitations (SELECT only, single statement, paging). However, it does not explicitly name query_database as an alternative, so the situational contrast is slightly weaker than ideal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tablesList Database TablesA
Lists every table in the e-commerce database with a plain-language explanation of what it holds, its row count, and its column names. Also returns the relationships between tables and the convention this database uses for revenue. Use this first when you need to know what data exists, or to answer questions about the database's structure. Reads SQLite directly: no LLM call, no API key, no cost, returns immediately. Returns JSON.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that it reads SQLite directly, makes no LLM call, requires no API key, costs nothing, returns immediately, and returns JSON. This is comprehensive behavioral disclosure beyond what the empty schema provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is moderately lengthy but every sentence adds valuable information: primary output, use-case guidance, and technical behavior. It is front-loaded with the main purpose and remains readable without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with no output schema, this description is entirely sufficient. It covers what the tool returns (table lists, explanations, row counts, columns, relationships, revenue convention), when to use it, and how it executes. Nothing an agent needs to decide to call it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema requires no explanation. Baseline for 0 params is 4, and the description appropriately does not invent parameter information. No additional semantics needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb and resource: lists every table in the e-commerce database, with a plain-language explanation of contents, row count, and column names. It also mentions relationships and revenue convention, distinguishing it from sibling tools like describe_table which likely focuses on a single table.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent to use this first when needing to know what data exists or answer database structure questions. It does not name sibling tools directly or state when not to use it, but the stated context is sufficient for an agent to decide.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_databaseAsk About the Online ShopA
Answers questions about the online shop in plain language: customers, products, stock, orders and sales. Ask it the way a shop owner would ask a colleague — no SQL, no table names, no technical wording needed.
USE THIS for any question about the shop or the business behind it, however casually it is phrased. For example: 'what sells best?', 'how many customers do we have?', 'which products are nearly out of stock?', 'how much did we earn last month?', 'who are our biggest spenders?', 'are any orders stuck in processing?', 'what was in order 42?', 'which category makes the most money?', 'how many orders were cancelled?'.
IT KNOWS ABOUT: customers (names, email, phone, when they signed up), products (name, category, price, stock on hand), orders (date, status — new, processing, shipped, completed, cancelled — and total), and the individual products inside each order (quantity and price paid).
RETURNS: a written answer in everyday language, with Markdown tables when a list or comparison helps. Numbers are read out of the text rather than returned as structured data.
GOOD TO KNOW: it can only look things up — it can never add, change or delete anything, and any request to do so is refused. One answer covers at most 100 rows of data. It asks a language model to write the SQL behind the scenes, so it needs an API key (or a local Ollama) configured, takes a few seconds, and may phrase the same question slightly differently between runs.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | The question about the shop, in plain language — pass the user's own wording where possible (e.g. 'What are our top 5 bestselling products?', 'How many orders were completed in May 2026?', 'Which customers have ordered more than 3 times?', 'What is running low on stock?') | |
| include_sql_details | No | Whether to show the SQL query and timing details underneath the answer. Set to false for a clean, non-technical answer (default: true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It extensively discloses read-only behavior, refusal of write attempts, a 100-row limit, dependence on an LLM/API key or Ollama, variability between runs, and return format (Markdown tables, numbers read out). This goes well beyond typical disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with clear sections (USE THIS, IT KNOWS ABOUT, RETURNS, GOOD TO KNOW) front-loaded with the core purpose. While lengthy, every sentence adds value and the section headers make it easy to scan. No redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Comprehensive for a natural-language query tool with no annotations and no output schema. It covers scope, entity data, return format, limitations, prerequisites, and refusal behavior. An agent has all necessary information to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers 100% of parameters with detailed descriptions. The description adds value by reinforcing plain-language usage and clarifying that numbers are read from text rather than returned as structured data. It also implies the message should be a natural question, which complements the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States that it answers questions about the online shop in plain language, covering customers, products, stock, orders, and sales. Clearly distinguishes itself from siblings by noting no SQL, table names, or technical wording are needed, implying execute_sql and schema tools are for different tasks.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'USE THIS for any question about the shop or the business behind it' and provides numerous examples. However, it does not explicitly name alternative tools or give a when-not-to-use clause; the no-SQL instruction implies but does not explicitly state that execute_sql is for raw queries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
describe_table - First observed
execute_sql - First observed
list_tables - First observed
query_database
TDQS
Scored across 4 tools
Each tool has a distinct, non-overlapping purpose: raw SQL execution, schema listing, table detail inspection, and natural-language querying. No ambiguity between them.
All tools follow a consistent verb_object pattern (execute_sql, list_tables, describe_table, query_database). Naming is uniform and predictable.
Four tools is well-scoped for a read-only SQL MCP server. Each tool adds clear value without redundancy, and the count is ideal for the domain.
The server fully covers its read-only analytics purpose: schema exploration (list, describe) and data retrieval (raw SQL and natural language). No missing operations or dead ends within its stated scope.
Maintenance
Related MCP Connectors
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Query your warehouse or a CSV with Claude/ChatGPT over MCP, governed by table-level ACL + audit.
Text-to-SQL MCP server: read-only queries on PostgreSQL, MySQL and SQL Server with your real schema
Ask questions in plain language, get answers from your business database. No SQL required.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to read-only analyze a SQLite e-commerce database, exploring schema and running analytical SQL queries over stdio.-
- FlicenseAqualityBmaintenanceGives AI agents read-only analytical access to an e-commerce SQLite database (customers, orders, order_items, products) via SQL queries, table listing, and schema inspection.3-
- FlicenseAqualityCmaintenanceEnables AI agents to analyze an SQLite e-commerce database via secure read-only SQL queries, providing tools for table inspection and analytical requests.2-
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to query an SQLite e-commerce database read-only, supporting analytical questions about customers, products, orders, and revenue.-