tabulite-mcp
Tabulite MCP
スプレッドシートには大きすぎ、チャットに貼り付けるにも大きすぎるCSVファイルを分析するには、データそのものではなく、ローカルのSQLiteランタイムをAIアシスタントに渡します。
Tabulite MCP(略称Tabulite)は、ローカルMCPサーバーです。CSVファイルのフォルダを指定すると、デスクトップのAIクライアントがそれらをSQLiteにインポートし、カラムに実際に何が入っているかを調べ、SQLを書いて質問に答えることができます — データの1行たりともマシンの外に出たり、会話に入り込んだりすることはありません。
Desktop AI client → MCP → Tabulite → sqlite3 → your CSV files
(the reasoning) (safe, deterministic tools)サーバーの中にLLMはありません。考えるのはAIクライアントです。Tabuliteは、考えるためのメタデータ、探索のための読み取り専用SQLインターフェース、そして答えが文章ではなくデータセットである場合のディスクへの直接パスを提供します。
なぜ
500 MBのCSVについてAIに尋ねるとき、選択肢はどれも悪いものばかりです:サンプルを貼り付ければ答えを失い、全体をアップロードすればコンテキストウィンドウを消費し(そしてデータをどこかに送ることになり)、自分でスクリプトを書くことになります。
1台のマシンと1つのSQLiteファイルがあれば、このサイズでも余裕で処理できます。Tabuliteはそのランタイムをデータの隣に配置し、MCP経由で公開します。アシスタントは数百トークンのカラムプロファイルを読み、SQLを書き、集計結果を受け取ります。行データはディスクに残ったままです。
向いている用途: 自分のラップトップでのCSVエクスポート、ログダンプ、抽出データの単発分析 — Excelでは扱いきれなくなったが、1台のマシンに収まるべきファイル。 向いていない用途: 本番パイプライン、定期ETL、マルチユーザーアクセス、または本物のデータウェアハウスに属するものすべて。
Related MCP server: csv-mcp-server
クイックスタート
必要環境: Docker Desktop(またはDocker Engine + Compose)。これだけです — Pythonのセットアップは不要です。
git clone https://github.com/davidmrguo/tabulite-mcp.git
cd tabulite-mcp
docker compose up --buildサーバーは現在 http://localhost:8000/mcp で稼働しており、ヘルスチェックは http://localhost:8000/health にあります。
2つの小さなサンプルCSV(source/sales.csv、source/customers.csv)がリポジトリに同梱されているので、すぐに試せます。AIクライアントを接続し(下記)、次のように尋ねてみてください:
「sales.csvを分析して。どのチャネルが最も収益を生み出した?」
アシスタントは list_sources()、import_source("sales.csv")、profile_table("sales") を呼び出し、次のようなSQLを書きます:
SELECT channel,
SUM(TRY_REAL(revenue)) AS revenue,
COUNT(TRY_REAL(revenue)) AS valid_rows,
COUNT(*) AS total_rows
FROM sales
GROUP BY channel
ORDER BY revenue DESC;AIクライアントを接続する
Claude Code
claude mcp add --transport http tabulite http://localhost:8000/mcpJSON設定を持つクライアント(Claude Desktop、Cursorなど):
{
"mcpServers": {
"tabulite": {
"type": "http",
"url": "http://localhost:8000/mcp"
}
}
}stdioのみに対応したクライアント: URLの前に mcp-remote のようなブリッジを配置します。
自分のデータを使う
CSVファイルを source/ に置くだけです — 再起動は不要です:
cp ~/Downloads/huge_export.csv source/ファイルは読み取り専用でマウントされ、gitignoreされているため、コミットされることも、サーバーが変更することもありません。Tabuliteが作成するもの(データベース、エクスポート)はすべて workspace/ に置かれます。
AIが使えるツール
Tool | 機能 |
|
|
| カラム、区切り文字、数件のサンプル行 — インポートなし |
| CSVをSQLiteにストリーミングしてプロファイリングする |
| インポート済みテーブル(行数と由来付き) |
| 全カラムのコンパクトなプロファイル |
| 1つのカラムの詳細(例付き) |
| 数行のデータ — データの見た目を確認するため |
| 読み取り専用の分析SQL(最大1,000行) |
| 完全な結果をファイルにストリーミングする |
特筆すべきは、ドメイン固有のものが一切ないことです。top_products() や calculate_revenue() はありません。SQLを書くのはアシスタントであり、それがこの設計の要点です — 誰も予期しなかった質問にも答えられます。
仕組み
CSVフィールドは意図的にTEXTとして保存される
インポートされたすべてのカラムは TEXT です:
CREATE TABLE sales (
transaction_id TEXT,
transaction_date TEXT,
revenue TEXT,
quantity TEXT
);インポート時に型を推測すると、誰もデータを見る前にデータが壊れます:"1,234" は 1 になり、先頭ゼロの製品コードは整数になり、"2025-13-40" は黙ってNULLになります。そこでストレージはファイルの記述をそのまま保持し、解釈は後で、可視かつ可逆な形で行われます。
プロファイルがカラムの意味をAIに伝える
インポート後、すべてのカラムがプロファイリングされ、結果は workspace/catalog.sqlite に保存されます。以下は同梱サンプルでの実際の出力です:
column logical_type confidence nulls invalid recommended_cast
transaction_id TEXT 1.000 0 0 none
transaction_date DATE 1.000 0 0 TRY_DATE
customer TEXT 1.000 0 0 none
product TEXT 1.000 0 0 none
channel TEXT 1.000 9 0 none
quantity INTEGER 0.996 0 2 TRY_INTEGER
revenue REAL 0.996 36 2 TRY_REALprofile_column("sales", "revenue") はさらに踏み込み、実際の問題値を表示します:invalid_examples: ["pending", "unknown"]。
推論は控えめです — 非NULL値の99%以上がその型としてパースできる場合にのみ型が割り当てられます。プロファイルはAIへの証拠であり、ストレージ層への指示ではありません。インポート済みデータが推測に合わせて書き換えられることは決してありません。
CAST の代わりに TRY_* 関数
SQLiteの CAST は危険なほど寛容です:
CAST('unknown' AS REAL) -- 0.0 ← quietly wrong
CAST('12 apples' AS REAL) -- 12.0 ← quietly wrong数千個の 'unknown' 値を含むカラムに対する AVG() は、黙ってゼロとして平均に含めます。そこでTabuliteはすべての接続で厳密な変換を登録します:
TRY_REAL('125.5') -- 125.5
TRY_REAL('') -- NULL
TRY_REAL('unknown') -- NULL他にも TRY_INTEGER、TRY_DATE、TRY_DATETIME、TRY_BOOLEAN が利用できます。SQLiteの集計関数はNULLをスキップするため、不正な値はゼロとして数えられるのではなく除外され、アシスタントは分母を確認できます:
SELECT AVG(TRY_REAL(revenue)) AS average_revenue,
COUNT(TRY_REAL(revenue)) AS valid_rows, -- 462
COUNT(*) AS total_rows -- 500
FROM sales;欠損データと不正データは区別されたまま
設定された欠損値マーカーのみがSQL NULL になります。単にパースに失敗した値は、書かれたとおりに保持されます:
CSVの値 | 保存される値 |
|
|
(空) |
|
|
|
|
|
|
|
デフォルトのマーカー:空文字列、NULL、null、N/A、NA。「このフィールドは空だった」と「このフィールドにはゴミが入っていた」は異なる発見であり、インポート時にそれらをまとめてしまうと、目に見える価値のあるデータ品質の問題が隠れてしまいます。
ファイルは名前ではなく内容で識別される
sales.csv を sales_FINAL_v2.csv にリネームして再インポートすると、Tabuliteは内容を認識し、テーブルを複製せずに既存のものを再利用します。同一性はファイルのSHA-256であり、別途の読み取りではなくインポート処理の最中に計算されます。1バイト変えると、独自のテーブルを持つ新しいソースになります。
インポートされたものはすべて1つのデータベース(workspace/databases/main.sqlite)に格納されるため、アシスタントは通常のSQLでファイルをまたいでJOINできます。2つのファイルが同じテーブル名を名乗る場合 — たとえば異なる2つのフォルダに sales.csv がある場合 — 2つ目は自身のコンテンツハッシュから接尾辞を取得します(sales と sales_4b11d3)。つまり、特定のファイルはインポート順に関係なく常に同じテーブル名になります。
大きな結果はチャットではなくディスクへ
query_sql() は最大1,000行を返し、常にその旨を伝えます("truncated": true)。これは、大きな結果を会話にページ分割するのではなく、SQLで集約するよう促すものです。病的なクエリ — 意図しないデカルト積、無制限の再帰CTE — はタイムアウト後にキャンセルされます。
ユーザーが実際に行データを欲しい場合、export_query() は同じ読み取り専用SQLを行数制限なしで実行し、カーソルを workspace/exports/ 配下のファイルに直接ストリーミングします:
「2025年の$1,000超のメール取引をすべて取得して、エクスポートして」
アシスタントはクエリを作成し、export_query() を呼び出してパスを返します — これが同梱サンプルデータでの実際の結果です:
{"file_name": "email_2025_high_value.csv",
"relative_path": "exports/email_2025_high_value.csv",
"row_count": 58, "file_size_bytes": 3084}サーバーも会話も結果全体を保持することはないため、58行でも500万行でも同じように動作します。
安全性
CSVが変更されることはありません。 source/ はDockerレベルで読み取り専用マウントされます。書き込まれるものはすべて workspace/ に置かれます。
AIが生成したすべてのクエリは読み取り専用であり、4つの層で強制されます:
接続は
file:…?mode=roとして開かれるため、OSがファイルを読み取り専用で保持します;PRAGMA query_only=ONにより、SQLite自体がそのハンドルへの書き込みを拒否します;拡張機能の読み込みが明示的に無効化されます;
set_authorizer()コールバックはSQLITE_SELECT、SQLITE_READ、SQLITE_FUNCTION(ファイルシステムに到達する組み込み関数を除く)、SQLITE_RECURSIVEのみを許可し、それ以外のすべて — 書き込み、スキーマ変更、ATTACH/DETACH、すべてのPRAGMA、トランザクション制御、メンテナンス — を拒否します。
第4層が実際のメカニズムです。これはステートメントの準備中にSQLite内部で実行されるため、クエリのテキストがどう綴られているかではなく、クエリが何を行うかを判断します。その前にSQLスクラバーが多層防御として配置され、モデルに素の not authorized ではなく読みやすいエラー(only read-only statements are allowed; found 'DROP')を返します。
この区別は両方向に働き、テストスイートがそれを固定しています:CASE … END と replace() スカラー関数は通常の分析SQLとして動作し続けますが、REPLACE INTO、PRAGMA writable_schema = ON、load_extension() は拒否されます。
パスは閉じ込められます。 サーバーは source/ 内でのみ読み取り、workspace/exports/ 内でのみ書き込みます。トラバーサル(../)、絶対パス、プロジェクト外を指すシンボリックリンクは拒否されます。エクスポートのファイル名はサニタイズされ、既存のエクスポートが上書きされることはありません。
認証はありません — 設計によるものです。コンテナは 127.0.0.1 にのみ公開され、同じマシン上のクライアントを想定しています。ネットワークに公開しないでください。
設定
すべてオプションです。compose.yaml で設定します。
変数 | デフォルト | 制御内容 |
|
| 読み取り専用のソースディレクトリ |
|
| 書き込み可能なワークスペース |
|
| SQL NULLとしてインポートされる値 |
|
| 対話型クエリの行数上限 |
|
| クエリがキャンセルされるまでの秒数 |
|
| エクスポートがキャンセルされるまでの秒数 |
|
| インポート中の |
|
| コンテナ内のバインドアドレス |
| localhost origins | オリジン許可リスト(DNSリバインディング保護) |
プロジェクト構成
tabulite-mcp/
├── source/ # your CSV files (read-only mount, gitignored)
├── workspace/ # everything generated (gitignored)
│ ├── catalog.sqlite # source, import, profile and export metadata
│ ├── databases/main.sqlite# the imported analytical tables
│ └── exports/ # query results written to disk
├── src/tabulite_mcp/
│ ├── server.py # the MCP tools
│ ├── config.py # paths and limits
│ ├── security.py # path containment + read-only enforcement
│ ├── database.py # connections, row caps, cancellation
│ ├── importer.py # streaming CSV → SQLite
│ ├── profiler.py # logical type inference
│ ├── casting.py # TRY_* functions
│ ├── catalog.py # catalog.sqlite
│ └── exporter.py # streaming results to files
├── tests/
├── Dockerfile
└── compose.yaml開発
Dockerなしで実行する:
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
TABULITE_SOURCE_DIR=./source TABULITE_WORKSPACE_DIR=./workspace tabulite-mcpテストを実行する:
pytest211のテストが以下をカバーしています:ソースの検出とトラバーサル拒否、ストリーミングインポート、NULLと不正値の処理、SHA-256による同一性(リネームおよび変更されたファイルを含む)、決定論的なテーブル命名、プロファイリングと型推論、TRY_* 関数、不正値を無視する AVG、SELECT/GROUP BY/CTE/join/window クエリ、結果の制限、クエリキャンセル、スクラバー層とオーソライザー層の両方での読み取り専用の強制、CSVおよびJSONエクスポート、エクスポートのストリーミング、ファイル名のサニタイズ、そして実際のインプロセスMCPセッションでのツール呼び出し。
技術スタック: Python 3.11+、標準ライブラリの sqlite3、そして mcp==2.1.1 に固定された公式MCP Python SDK(v2 API:MCPServer、ホスト/ポートは run() で指定)。pandasもNumPyもORMもなし — 中核は一目でわかる普通のPythonです:sqlite3.connect()、conn.executemany()、conn.create_function()、cursor.fetchmany()。
スケール: 133 MB / 2,000,000行のCSVは、コンテナメモリが約100 MBでほぼ一定のまま、約2分でインポートおよびプロファイリングが完了します。集計には数秒かかります。インポートはRAMではなくディスクに依存します。
トラブルシューティング
ポート8000が使用中 — compose.yaml のマッピングのホスト側を変更し("127.0.0.1:8001:8000")、クライアントが新しいポートを指すようにしてください。
クライアントが接続できない — curl http://localhost:8000/health でサーバーが起動しているか確認し、次に docker compose logs -f を実行してください。
workspace/ への書き込みでパーミッションエラー(Linux) — compose.yaml の user: 行のコメントを解除して、コンテナユーザーではなく自分のユーザーとしてファイルが作成されるようにしてください。
source/ 内のファイルが一覧に表示されない — 検出されるのは .csv と .tsv のみで、ドットファイルはスキップされます。
CSV編集後に「不明なテーブル」 — ファイルを変更するとハッシュが変わるため、import_source() を再実行してください。新しい内容には独自のテーブルが作成されます。
対象外
組み込みLLM、サーバー内での自然言語からSQLへの変換、任意のPythonコードの実行、pandas/NumPy/matplotlib、Excel、DuckDB、Polars、Parquet、埋め込みやベクトル検索、クラウドデプロイ、認証、マルチユーザー対応、バックグラウンドジョブはいずれも対象外です。AIクライアントがすでにインターフェースであり、推論レイヤーです。
ライセンス
MIT — 好きなように使って構いませんが、著作権表示は保持してください。
コントリビューションを歓迎します。同じライセンスの下で受け付けます(CLAなし、著作権の譲渡なし)。著作権がコードを書いた人に残るのは意図的で、このプロジェクトが誰かの製品になるのではなく、オープンソースプロジェクトであり続けることを目的としています。
This server cannot be installed
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 gradedqualityDmaintenanceAI-first CSV analysis tool that enables AI agents to analyze, query, and audit large CSV files directly within conversations, turning raw data into actionable insights.2
- FlicenseBqualityDmaintenanceEnables Claude to directly access, query, and analyze local CSV files using natural language, keeping data private and local.41
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with local CSV and Parquet data files through natural language queries, facilitating tasks like summarizing datasets or retrieving specific information.5
- AlicenseNot gradedqualityDmaintenanceEnables querying Excel and CSV files using SQL via natural language, allowing AI assistants to analyze data without manual SQL writing.1MIT
Related MCP Connectors
Explore, query, and inspect SQLite databases with ease. List tables, preview results, and view det…
Connect AI assistants to your GitHub-hosted Obsidian vault to seamlessly access, search, and analy…
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
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/davidmrguo/tabulite-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server