はじめに / 対象と前提
Claude Code などの AI エージェントから MCP(Model Context Protocol)経由で Notion API を叩いて、タスク管理用データベースを検索・集計している人向けの記事。
前提環境:
- Claude Code(2026年8月時点の最新版)
- Notion 公式 MCP サーバー(ローカル起動、トークン認証)
- Python 3.13(後処理スクリプト用)
「DB からレコード一覧を取ってくるだけの単純なクエリのはずが、なぜかツール呼び出し自体がエラーで落ちる」という現象にハマったので、原因と対策を実装レベルでまとめる。
TL;DR
- Notion の data source を
query-data-sourceで検索する際、フィルタ条件が緩い・プロパティを絞らずに投げると、たった 30 件でも約 10 万文字のレスポンスになり、ツール呼び出し自体が「トークン上限超過」でエラー終了する - 応急処置(結果をファイルに保存して文字数レンジで分割読み込み)は動くが対症療法にすぎない
- 恒久対策は
filter_propertiesで必要なプロパティだけに絞ることとpage_sizeを下げること。実際に試して効果を確認した
手順 / 動かし方
1. 再現させる
フィルタは付けるが、プロパティは絞らず page_size も大きめのまま投げる。
{
"data_source_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"filter": { "property": "ステータス", "select": { "equals": "Posted" } },
"sorts": [{ "property": "投稿日時", "direction": "descending" }],
"page_size": 50
}
該当が 30 件あるデータベースで実行すると、各ページに紐づく本文プロパティ(リッチテキストのメモ、リレーション、数値、URL など)がすべて返ってきて、レスポンス全体が 96,757 文字に達し、以下のようなエラーで即座に失敗した。
Error: result (96,757 characters across 1 line) exceeds maximum allowed tokens.
Output has been saved to /path/to/tool-results/xxxx.txt
2. 応急処置: 保存済みファイルを分割読み込み
エラー時に結果がファイルへ保存されるので、Python で範囲指定して読む。
import json
with open("/path/to/tool-results/xxxx.txt") as f:
data = json.loads(f.read())
for r in data["results"]:
props = r["properties"]
print(props["タイトル"]["title"][0]["plain_text"])
これで中身は確認できるが、ツール呼び出し 1 回で完結しないので毎回ファイルパスのやり取りが挟まり、MCP の手軽さが失われる。根本対策ではない。
3. 恒久対策その1: filter_properties でプロパティを絞る
filter_properties には プロパティ名ではなくプロパティ ID を渡す。ID はページ作成・取得時のレスポンスに含まれる properties.<プロパティ名>.id を控えておけばよい。
{
"data_source_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"filter": { "property": "ステータス", "select": { "equals": "Posted" } },
"filter_properties": ["title", "_QfP", "%5EaCu", "%3CrdM"],
"page_size": 5
}
実行すると、各ページの properties オブジェクトが指定した 4 つ(タイトル・ステータス・投稿日時・タグ)だけに絞られ、メモ・エラー欄・価格・売上・購入数・カテゴリ・リレーションといった今回使わないプロパティが消えることを実機で確認した。
4. 恒久対策その2: page_size を絞る
一覧性が不要なら page_size を 50 → 5〜10 に下げるだけでも効果は大きい。ページ送りが必要な場合はレスポンスの next_cursor を次のリクエストの start_cursor に渡して回す。
ハマりどころ
-
filter_properties は「プロパティ名」ではなく「プロパティ ID」を渡す仕様。
"投稿日時"のような名前を渡しても無視されるか型エラーになる。 -
ID は URL エンコードされたまま返ってくることがある(例:
%5EaCu)。自分でデコードし直す必要はなく、そのままコピペで動く。 -
filter_properties が削るのは
propertiesオブジェクトだけ。 ページのid/url/created_time/last_edited_time/parentなどのメタ情報は必ず返る。プロパティ数が多いデータベースほど効果が大きいが、ゼロにはならない。 -
title プロパティだけ ID が固定文字列
"title"。 他のプロパティはランダムな ID が振られているので、最初に見ると挙動が違って戸惑う。 - 応急処置でファイル化された JSON を扱うとき、シェルのワンライナーだと日本語プロパティ名のクォート処理を誤りやすい。ヒアドキュメントかスクリプトファイル経由にすると事故が減る。
背景・補足
MCP 経由のツール呼び出しは、少なくとも Claude Code のようなエージェント実行環境では 1 回のレスポンスで使えるトークン数に上限がある。これは Notion に限らず、ページネーションや全文検索の結果を返す MCP サーバー全般で起こりうる。「取れるだけ取る」クエリを投げると簡単に上限を踏み抜くので、必要な列だけ要求するという API 設計上の基本が、AI エージェント経由の呼び出しでもそのまま効いてくる。
まとめ
- Notion 系データベースを MCP 経由でクエリしてトークン上限エラーに当たったら、まず
filter_propertiesでプロパティを絞る -
filter_propertiesにはプロパティ「ID」を渡す(名前ではない、URL エンコードされたままで OK) - それでも足りなければ
page_sizeを下げてページネーションする - 応急処置(ファイル保存+分割読み込み)は原因を直すまでのつなぎと割り切り、根本対策とセットで運用する