過去記事482本から作った記事再現ガイドを、TiDBとCloudflare WorkersのリモートMCPサーバーにしてみた

過去記事482本の分析から作った記事制作ガイドをTiDBにセクション単位で保存し、Cloudflare Workers上の読み取り専用Remote MCPから配信する仕組みを、設計のポイントに絞って紹介します。

約9分で読めます8 SECTIONS

こんにちは、どんべーです。

「自分らしく書いて」とAIに頼むたびに、文体の資料をプロンプトに貼るのは手間がかかります。全部貼れば関係ない統計まで渡りますし、文字数で切ればルールとその適用条件が離れてしまいます。

そこで、過去記事482本の分析から作った記事制作ガイドをTiDBに保存し、Remote MCPから配信する仕組みを作りました。これによって、どのAIツールからでも自分の記事の特徴を考慮した記事が制作できることになり、ローカルスキルよりも汎用性が高いコンテキストデータにすることができます。

AIは「本文を生成したい」「タイトルを評価したい」と用途を伝えるだけで、必要な部分をまとめて受け取れます。

482本から何が分かったかは、noteの記事(公開予定)にまとめています。この記事ではどう作ったかを紹介します。

この記事で分かること

  • 記事制作ガイドをAIに渡しやすい単位に分ける考え方
  • 用途を指定すると、必要な部分だけをまとめて返すMCPツールの作り方
  • Notionで編集した内容をTiDBへ同期する流れ

全体像

Notionのデータソースを同期WorkerがTiDBへ反映し、読み取り専用のMCP Workerを通してClaude CodeやCodexへ配信する流れ

人はNotionで記事制作ガイドを編集します。同期用のWorkerがそれをTiDBへ反映し、MCP用のWorkerがAIからの問い合わせに答えます。どちらもCloudflare Workersで動かしています。

書き込む側と読む側を別のWorkerに分けたのがポイントです。MCP Workerはデータを読むだけなので、AIがガイドを書き換えることはありません。

やってみた

1. 記事制作ガイドをセクションに分ける

記事制作ガイドは過去記事482本を集計した結果を「AIが守るルール」に直したものです。たとえば「タイトルの47.5%に数字が入っている」という観察は、「価格・日付・性能など、判断材料になる数字を落とさない」というルールにしました。平均値をそのまま命令にすると、AIが平均に寄っていくからです。

ガイドはMarkdownで書き、見出しで区切ったセクションを配信の単位にしています。

  • H2:意味が完結するまとまり。AIにはこの単位で返す
  • H3:検索で当てるための小さなまとまり

H3で見つけたら、親のH2ごと返します。文字数で機械的に切らないので、ルールとその適用条件が離れません。

各セクションには ore-title/core や ore-body/longform/contract のような固定キーを付けました。AIは見出しの文言を探さず、キーで必要なセクションを受け取ります。

2. TiDBには「文書」と「セクション」の2テーブルだけ置く

テーブルは文書を1行で持つものと、セクションを1行ずつ持つものの2つです。主な列だけを抜き出すと次のようになります。

CREATE TABLE author_style_documents (
  document_id VARCHAR(128) PRIMARY KEY,
  source_markdown MEDIUMTEXT NOT NULL,
  routing_manifest_json JSON NOT NULL
  -- 省略
);

CREATE TABLE author_style_current_sections (
  document_id VARCHAR(128) NOT NULL,
  section_id VARCHAR(255) NOT NULL,
  context_key VARCHAR(255) NULL,
  delivery_markdown MEDIUMTEXT NOT NULL,
  -- 省略
  PRIMARY KEY (document_id, section_id)
);

「どの用途にどのセクションを返すか」の対応表は、文書側の routing_manifest_json にJSONで持たせています。

最初はもっと細かく5テーブルで設計していました。AIが読むだけの用途には細かすぎたので、削って今の形にしています。

3. 用途を指定して、必要なセクションをまとめて受け取る

MCPツールは通常の取得用の get_author_style_context と、根拠を確かめるときだけ使う search_author_style_evidence の2つです。

普段使うのは前者です。「タイトルか本文か」「生成か評価か」「どんな記事か」「どのくらいの長さか」を引数で渡します。

{
  "name": "get_author_style_context",
  "arguments": {
    "documentId": "ore-body-style",
    "operation": "generate",
    "mode": "explanatory",
    "lengthBand": "2001plus"
  }
}

この例では、長めの解説記事の本文を書くためのルールが13セクション分、1つのMarkdownにまとまって返ってきます。サーバー側でセクションを選ぶので、AIは何度も問い合わせる必要がありません。

482本の統計そのものは、普段は返しません。AIが平均値に引っ張られないよう、根拠を確かめたいときだけもう1つのツールで読む形にしています。

4. 上限を超えたら切り捨てずにエラーにする

まとめた結果が上限(45,000字)を超えたら、末尾を切って返すのではなくエラーにしています。

if (markdown.length > manifest.maxContextChars) {
  throw new AuthorStyleContextTooLargeError(markdown.length, manifest.maxContextChars);
}

途中で切れると、例外や禁止の条件だけが抜け落ちたルールが届いてしまいます。それなら返さないほうが安全です。

5. Notionで「Ready」にしたら同期する

データソースはNotionのデータベースに置いています。編集を終えてStatusを Ready にすると、次の流れでTiDBへ反映されます。

  1. NotionのWebhookを同期Workerが受け取る
  2. 本文を検証してセクションに分け、TiDBを更新する
  3. NotionのStatusを Synced に書き戻す

失敗したときはStatusが Error になり、TiDBには前の内容が残ります。同期が止まっても、MCPからの配信は止まりません。

当初は1分ごとに同期する案もありましたが、そんなに頻繁には更新しないのでWebhookにしました。

ハマったところ

AIが書いた下書きの段落が、妙に短くなることがありました。一文の平均は、下書きが34.9字、僕が直した後が46.1字です。

原因の一つはガイドにありました。過去記事は短いニュースが中心だったので、「1段落1〜2文」という観察を、長い記事にも当てはめるルールにしていたのです。長文用のルールを別に足し、過去の観察には「ORE観察」と印を付けて、生成ルールと区別しました。

最小構成で試すなら

最初から全部作る必要はありません。文書1つ、テーブル1つ、ツール1つで始められます。

CREATE TABLE style_sections (
  document_id VARCHAR(64) NOT NULL,
  context_key VARCHAR(128) NOT NULL,
  title VARCHAR(255) NOT NULL,
  markdown MEDIUMTEXT NOT NULL,
  PRIMARY KEY (document_id, context_key)
);
{
  "name": "get_style_section",
  "arguments": { "documentId": "my-title-style", "contextKey": "my-title/core" }
}

まずは「タイトルの書き方」をH2ごとに1行ずつ手で入れ、キーを指定して1セクションを返すだけで十分です。用途による選び分けやNotion同期は、使い方が固まってから足せば間に合います。

考え方と一部の構成は mycontext-public で公開しています(文体の部分は旧構成です)。

まとめ

  • 記事制作ガイドは、意味が完結するセクションに分けて固定キーにする
  • AIへ用途を伝えるだけで、必要なセクションをまとめて受け取る
  • 上限を超えたら切り捨てずにエラーにする
  • 書き込む側と読む側を分け、MCPは読み取り専用にする

参考

更新履歴

  • 2026年10月26日 公開。

LATEST STORIES

最新ブログ記事

AI活用と業務設計の現場で得た知見を、実例とともにお届けします。

すべての記事