Skip to content

Instantly share code, notes, and snippets.

@podhmo
Last active December 2, 2025 09:27
Show Gist options
  • Select an option

  • Save podhmo/6bb2017160a6a0d18bc69935e4a397b7 to your computer and use it in GitHub Desktop.

Select an option

Save podhmo/6bb2017160a6a0d18bc69935e4a397b7 to your computer and use it in GitHub Desktop.
Uploaded via Gist Uploader - 2025-12-02T09:20:05.872Z

ドキュメント用のMCPサーバーについて考えた

MCPのサーバーでドキュメント用のMCPサーバーが乱立するのはバカバカしいと思った。 加えてcontext7は不透明な感じがした。 何か良い落とし所はないか考えてみた話。

https://x.com/i/grok/share/ema1ivXpkAdXkTyRoV81HprZZ

grokとの対話履歴はノイズが多いかと思った。何か良い感じに備忘録的なメモを残せないかと作った記事がarticle1.mdとarticle2.md

透明な知のパイプライン:MCPドキュメントサーバーの進化論的探求

🔍 乱立するサーバーと「テキスト」への回帰

大規模言語モデル(LLM)1に外部知識を注入するための標準規格であるMCP(Model Context Protocol)2が登場した際、開発者たちの間に広がったのは、標準化への期待と共に一種の混乱でした。現状を観察すると、企業やライブラリ開発者がそれぞれ独自の実装でMCPサーバーを公開し、エコシステムが断片化していく様子が見て取れます。これは、ツールとモデルをつなぐという本来の目的を超え、マーケティング的な「自社専用接続口」の乱立を招いています。

ここで原点に立ち返る問いが生まれました。ドキュメント用のMCPサーバーにおいて、我々が本当に必要としている機能とは何でしょうか。

LLMが本質的に求めているのは、装飾されたHTMLではなく、意味構造が明確なプレーンテキスト、具体的にはMarkdownです。思考を進めると、ドキュメント用MCPの役割は驚くほど単純化できることに気づきます。それは、Web上のドキュメントをテキストとして返すエンドポイント、あるいはHTMLをテキストに変換するプロキシがあれば十分ではないか、という仮説です。

さらに、理想的な状態を定義するならば、その知識ソースは単一の組織によって管理されるのではなく、コミュニティの「集合知」によって合成され、維持されるべきです。そして何より、膨大なテキストの中から必要な情報を引き出すための「検索」機能が不可欠です。ここから、特定のクラウドベンダーやプロプライエタリな実装に依存しない、汎用的で透明性の高い仕組みが必要であるという方向性が定まりました。

🛠 抽象化の罠と透明性の欠如

汎用的な仕組みを構築するにあたり、既存のフレームワークやサービスの評価が必要となります。

まず、開発を容易にするフレームワークである fastmcp3 のようなツールを検討しました。これらはサーバー構築のボイラープレート(定型コード)を削減するには有用ですが、アーキテクチャの視点からは「低レイヤーすぎる」という課題が浮上します。これらを使って個別にサーバーを立てることは、結局のところ「車輪の再発明」を助長し、ドキュメント処理という特定ドメインに必要な抽象化(検索、読み込み、推薦といった共通インターフェース)を提供しません。

次に、既存のドキュメント提供サービス(例:Context7など)を検討しました。これらは「ライブラリ名を指定すればドキュメントが注入される」という利便性を提供する一方で、その裏側がブラックボックスであるという致命的な欠陥を抱えています。どのバージョンのドキュメントが読まれているのか、更新頻度は適切か、クロールロジックはどうなっているのか。これらが不透明なままでは、LLMの出力に対する信頼性を担保できません。

この分析から、目指すべきシステムの要件が明確になりました。それは、単にOSS(オープンソースソフトウェア)であるだけでなく、ドキュメントの取得・変換ロジックそのものが「透明」であり、誰でも検証・修正可能であることです。

📜 コードから設定へ:集合知を記述するJSON

透明性を確保しつつ、集合知によってメンテナンスされるシステムをどう実現するか。思考は、命令的なコードによる実装から、宣言的な設定による定義へとシフトしました。

ドキュメントサイトごとに異なるHTML構造を解析し、Markdownへ変換するロジックをPythonスクリプトなどで個別に記述していては、メンテナンスコストが肥大化し、セキュリティ上の懸念も拭えません。そこで導き出されたのが、「ドキュメントの構造定義をJSON設定ファイルに外出しする」というアイデアです。

具体的には、各ライブラリのドキュメントについて、以下の情報をJSONで定義します。

  1. 対象のURL
  2. タイトルや本文を抽出するためのXPath4やCSSセレクタ
  3. 不要な要素(ナビゲーションや広告など)の除去ルール
  4. ページネーションの辿り方

このアプローチの革新性は、プログラミングスキルを持たないユーザーでも、CSSセレクタさえ分かればドキュメントソースを追加・修正できる点にあります。GitHub上で設定ファイルに対するPull Requestを受け付ける体制を整えれば、特定のドキュメントが古くなったり構造が変わったりしても、コミュニティが即座に修正可能です。これにより、システムは「不透明なサービス」から「透明なルールの集合体」へと進化します。

🏗 動的プロキシと静的検証の分離

設定ファイルベースのアプローチが決まったところで、次は実行アーキテクチャの検討に移ります。当初は、変換されたMarkdownファイルをリポジトリにコミットして管理することも考えられましたが、これはGitリポジトリの肥大化と鮮度の低下を招きます。

そこで、責務を明確に分離するアーキテクチャが考案されました。

  1. リポジトリの役割: JSON設定ファイル(ソース定義)のみを管理する。これこそが人類の共有資産となる知識ベースです。
  2. CI(継続的インテグレーション)の役割: 設定ファイルが正しく機能するかを検証する。実際にページを取得し、セレクタが意図通りに要素を抽出できるかのみをテストします。
  3. ランタイム(プロキシ)の役割: 実際の変換処理を行う。ユーザー(MCPサーバー)からのリクエストを受け、オンデマンドで対象サイトへアクセスし、JSONのルールに従ってHTMLをMarkdownに変換して返します。

この構成により、リポジトリは軽量でクリーンな状態を保ちつつ、常に最新のWeb上の情報を取得できる動的なシステムとなります。キャッシュ機構をプロキシに組み込むことで、パフォーマンスと相手方サーバーへの負荷も制御可能です。

🌐 「静的」の理想と「動的」の現実

最後の課題は、現代のWebにおけるJavaScriptの扱いです。理想論としては、JavaScriptの実行を必要とせず、シンプルなHTTPリクエスト(curlなど)だけで情報が取得できる「静的HTML」のみを対象とすべきです。これはシステムを堅牢、軽量、かつ高速に保つための「Static First(静的優先)」の哲学です。JS必須のドキュメントはLLM時代の負債である、という強い立場を取ることも可能です。

しかし、現実には多くの有用なライブラリがSPA(Single Page Application)5としてドキュメントを提供しており、それらを完全に排除することは実用性を損ないます。

ここで思考は、原理主義的な排除ではなく、実用的な包含へと至りました。すなわち、プロキシサーバーの内部に「隔離されたヘッドレスブラウザ(Isolated Browser)」6を組み込むアプローチです。

ユーザーインターフェース(JSON設定)上はシンプルさを保ちつつ、裏側のプロキシが以下の判断を行います。

  • 基本的には軽量なHTTPリクエストで取得を試みる。
  • JS実行が必須なサイトに限り、サーバーサイドで安全に隔離されたブラウザを起動し、レンダリング結果(DOM)を取得する。
  • 認証情報などは一切持たせず、単なるレンダリングエンジンとして使い捨てることでセキュリティを担保する。

このハイブリッドな構成により、ユーザーは技術的な複雑さを意識することなく、「設定ファイルを追加するだけ」で、静的サイトから動的なSPAまであらゆるドキュメントをMCPのエコシステムに取り込むことが可能になります。

こうして、透明性が高く、集合知によって維持され、かつ現代のWeb事情にも適応したドキュメント用MCPサーバーのアーキテクチャが完成しました。

Footnotes

  1. 大規模言語モデル (LLM): 大量のテキストデータで学習されたAIモデル。ここではドキュメントの内容を理解し、回答を生成する主体として位置づけられる。

  2. MCP (Model Context Protocol): AIモデルと外部ツールやデータソースを接続するための標準化されたプロトコル。

  3. fastmcp: MCPサーバーを迅速に構築するためのフレームワークやライブラリの一種。

  4. XPath: XML形式の文書から特定の部分を指定して抽出するための記述言語。HTMLの解析にも用いられる。

  5. SPA (Single Page Application): ページ遷移を行わず、JavaScriptによって動的にコンテンツを書き換えるWebアプリケーションの形態。

  6. ヘッドレスブラウザ: 画面表示(GUI)を持たずにバックグラウンドで動作するWebブラウザ。プログラムによる自動操作やスクレイピングに利用される。

MCPによるドキュメント供給と透明性に関する思考ログ

🤔 現状のMCPエコシステムへの違和感

最近のMCP1の盛り上がりを見ていると、少し違和感を覚える。みんなこぞって「オレオレMCPサーバー」を作りたがっているけれど、それって本当に効率的なんだろうか。

特に fastmcp2 のようなライブラリを使って、低レベルなRPC3サーバーを量産している現状は、なにか抽象化のレベルを間違えている気がする。ドキュメントをLLM4に食わせたいだけなのに、なんで毎回ツール定義やリソースのエンドポイントをPythonで手書きしなきゃいけないんだ?

理想的には、AWSの aws-knowledge-mcp-server が提供しているようなインターフェースが標準であるべきだと思う。

# 理想的なインターフェースのイメージ
tools = [
  "search_document",  # 検索して該当ドキュメントのリストを返す
  "read_document",    # 指定されたドキュメントの中身をMarkdownで返す
  "recommend_docs"    # コンテキストに合わせて読むべきドキュメントを提案する
]

これがあれば十分なはずだ。なのに、実装の詳細が各サーバーに分散してしまっている。本来やりたいのは、HTMLではなくMarkdownなどのテキストを対象にLLMを実行すること。そのための「テキスト変換プロキシ」と「検索エンドポイント」があれば事足りるはずだ。

しかも、これを特定のベンダー(AWSとか)に依存せず、OSS5として透明な形で運用したい。Context76はアイデアとしては素晴らしいけれど、裏側でどうやってドキュメントを集めているのか、更新頻度はどうなっているのかがブラックボックスなのが怖い。

💡 設定ファイルによる宣言的な定義

透明性を確保するためには、ロジックをコードに埋め込むのをやめるべきだ。ドキュメントの取得ロジックをJSON設定ファイルとして切り出せば、誰でも検証できるし、PRを送るだけで新しいドキュメントソースを追加できる。「集合知」でドキュメントサーバーを育てるにはこれが一番早い気がする。

構成案としてはこんな感じか。

// sources/react-query.json
{
  "id": "react-query",
  "name": "TanStack Query",
  "base_url": "https://tanstack.com/query/latest",
  "list": {
    "type": "sitemap",
    "url": "https://tanstack.com/query/latest/sitemap.xml"
  },
  "selectors": {
    "title": "//h1",
    "content": "//div[@class='prose']",
    "remove": ["nav", "footer", "script"]
  }
}

こうやってXPath7やCSSセレクタで抽出ルールを定義しておけば、あとは汎用的なクローラーが勝手にMarkdownを作ってくれる。これなら、特定のライブラリのドキュメント構造が変わっても、JSONを修正するだけで済む。

でも待てよ、これを全部事前にクロールしてMarkdownファイルとしてリポジトリにコミットするのは筋が悪い気がする。Gitリポジトリが肥大化するし、情報の鮮度を保つのも大変だ。

🔄 動的プロキシへの転換

事前に全部Markdown化しておく必要はないかもしれない。必要なのは「検索用のインデックス」と「閲覧時のリアルタイム変換」だ。

CI8では「このJSON設定で正しくドキュメントが取得できるか」の検証だけを行って、実際の変換はリクエストが来たタイミングでプロキシサーバーがやればいいんじゃないか?

# proxy/server.py のイメージ

@app.get("/convert")
async def convert(url: str):
    # 設定ファイルをロード
    config = load_config_for_url(url)
    
    # HTML取得
    html = await fetch(url)
    
    # 設定に基づいて不要な要素を削除 & 抽出
    cleaned_html = apply_selectors(html, config)
    
    # Markdownへ変換
    markdown = markdownify(cleaned_html)
    
    return {"markdown": markdown}

これなら、MCPサーバー側はめちゃくちゃシンプルになる。

  1. ユーザーが search_documents を呼ぶ -> インデックス(FAISS9とか)から検索。
  2. ユーザーが read_document(url) を呼ぶ -> プロキシに投げてMarkdownを受け取る。

リポジトリにはJSONファイルだけが並ぶことになる。これこそが求めていた「透明性」だ。

❌ 静的取得の限界とSPAの壁

ここで一つ問題が出てくる。現代のWebドキュメントはJavaScriptだらけだ。curlhttpx でHTMLを取ってきても、中身が空っぽの <div id="root"></div> しかないなんてことはザラにある。Next.jsのApp Routerのドキュメントとか、React系のライブラリは特に怪しい。

最初は「JS必須なドキュメントなんてLLM時代の負債だ!無視してやる!」という過激な思想(Static First)で行こうかと考えた。

# CONTRIBUTING.md (案)
## 追加条件
- curlでコンテンツが取得できること。
- JS必須のサイトは受け付けません。

確かに思想としては綺麗だ。でも、実用性を考えるとこれはあまりに厳しすぎるかもしれない。開発者が本当に読みたいのは最新のフレームワークのドキュメントであって、それらがSPA10である現実は変えられない。思想のために利便性を捨てては、誰も使わないツールになってしまう。

🛠️ 隔離されたブラウザという妥協点

妥協案が必要だ。プロキシサーバー側で、必要に応じてヘッドレスブラウザ11を立ち上げるアプローチはどうだろう。

もちろん、セキュリティのリスクはある。任意のURLでブラウザを立ち上げさせるのは危険だ。でも、ここは「認証なし(No Auth)」かつ「隔離された環境(Isolated)」に限定すれば許容できる範囲かもしれない。ログインセッションなどは持たせず、単にパブリックなURLをレンダリングするだけ。

そうすると、JSON設定に rendering_mode みたいなフィールドが必要になるな。

{
  "id": "nextjs-docs",
  "rendering_mode": "browser", // ここで指定
  "wait_selector": "main h1",  // レンダリング完了の目安
  // ...
}

プロキシの実装も少し分岐する。

async def fetch_content(url: str, config: dict):
    if config.get("rendering_mode") == "browser":
        # Playwrightなどを起動して取得
        return await fetch_with_browser(url, wait_for=config.get("wait_selector"))
    else:
        # 軽量なHTTPリクエスト
        return await fetch_static(url)

これなら、基本は軽量な静的取得を優先しつつ、どうしても必要な場合だけブラウザという重い手段を取ることができる。複雑さはプロキシの中に隠蔽されるから、MCPを利用するクライアント側や、設定ファイルを書くコントリビューターからは、裏側でブラウザが動いているかどうかは気にしなくていい。

結局のところ、「透明性の高い設定ファイル」と「柔軟な実行環境(プロキシ)」の分離こそが、このアーキテクチャの肝になりそうだ。

Footnotes

  1. MCP (Model Context Protocol): AIモデルと外部データやツールを接続するための標準プロトコル。

  2. fastmcp: MCPサーバーを簡単に構築するためのPythonフレームワークだが、抽象度が低くボイラープレートになりがちという指摘がある。

  3. RPC (Remote Procedure Call): 遠隔手続き呼び出し。ここではMCPが関数呼び出しのような形で機能することを指す。

  4. LLM (Large Language Model): 大規模言語モデル。

  5. OSS (Open Source Software): オープンソースソフトウェア。

  6. Context7: LLMに最新のライブラリドキュメントを注入する既存のMCPサーバーサービス。便利だが内部挙動が不透明。

  7. XPath: XML形式の文書から特定の部分を指定して抽出するための言語。HTMLのスクレイピングによく使われる。

  8. CI (Continuous Integration): 継続的インテグレーション。ここではGitHub Actionsなどの自動テスト環境を指す。

  9. FAISS: Facebook AI Similarity Search。ベクトル検索を行うためのライブラリ。

  10. SPA (Single Page Application): 単一のWebページでアプリケーションを構成し、JavaScriptで動的にコンテンツを書き換える仕組み。

  11. ヘッドレスブラウザ: GUIを持たずにコマンドラインやプログラムから制御できるWebブラウザ。PlaywrightやPuppeteerなどが有名。

対話履歴

ユーザー: 添付したドキュメントは私とaiであるgrokとのMCPサーバー特にドキュメントに対するサーバーの実装に対する対話の履歴。トーンは落ち着いた形にしつつ推移をまとめて。


AI: ご提示いただいた対話履歴に基づき、ドキュメント用MCP(Model Context Protocol)サーバーの理想形とその実装方針に関する議論の推移を要約しました。

議論は、現状のMCPエコシステムへの問題提起から始まり、具体的なアーキテクチャの設計、そして最終的な運用哲学の確立へと段階的に深化しています。


ドキュメント用MCPサーバー実装に関する議論の推移

1. 現状への問題提起と理想形の定義

初期段階では、現在のMCPエコシステムにおける「各社・各ライブラリが独自のMCPサーバーを乱立させる風潮」や「fastmcpのような低レイヤーな実装への依存」に対する批判的な検討が行われました。 結論: ドキュメント用MCPは、特定のプラットフォーム(AWS等)に依存せず、汎用的かつ透明性の高いOSSとして実装されるべきであり、「HTMLではなくテキスト(Markdown)を返す」「集合知によって合成される」形が理想であると定義されました。

2. 透明性の確保と不透明な既存製品への対案

既存のドキュメント提供サービス(Context7など)は便利であるものの、更新ロジック等がブラックボックスである点が懸念されました。 提案: これに対し、ユーザーが検証・修正可能な「透明性の高い代替案」が必要であるとの合意に至りました。具体的には、ドキュメントの取得・変換ロジックをコードまたは設定として公開し、コミュニティ主導で維持する方向性が示されました。

3. 実装方式の具体化:JSON設定とXPathによる抽出

透明性と貢献のしやすさを両立させる具体的な実装手段として、**「ドキュメントごとの変換ルール(XPath/CSSセレクタ、ページネーション等)を記述したJSONファイル」**を中心とするアーキテクチャが考案されました。 メリット: これにより、プログラミングレスでドキュメントソースの追加・修正が可能となり、Pull Requestを通じた「集合知」によるメンテナンス体制が確立できるとされました。

4. アーキテクチャの最適化:動的プロキシ構成

当初の「変換済みMarkdownをGit管理する」案から、運用コストとリポジトリの軽量化を考慮した構成へシフトしました。 修正案: Markdown変換は常駐するプロキシサーバーが動的に行い、CI(GitHub Actions)は「JSON設定の正当性(正しく取得できるか)」のみを検証するフローへ変更されました。これにより、リポジトリは設定ファイル(ソース定義)の管理に特化することになりました。

5. 最終的な哲学の確立:「Static First」

議論の最終段階で、「JavaScript実行が必須なドキュメントはLLM時代の負債である」という重要な指針が提示されました。 決定事項: Playwrightのようなヘッドレスブラウザを用いた重量級のスクレイピングは廃止し、curl等で取得可能な静的HTMLのみを対象とする「Static First」なアプローチが採用されました。これにより、システムはより堅牢かつ軽量なものとなり、JS必須のドキュメントは対象外とする(あるいは静的化されるまで待つ)という明確な境界線が引かれました。


総括 議論は「汎用的なドキュメントサーバー」という構想からスタートし、最終的に**「静的サイトを対象とし、JSON定義による抽出ルールを集合知で管理する、透明性の高いプロキシ型MCPサーバー」**という具体的かつミニマルな実装解へと収束しました。

(返答終了理由: STOP)


ユーザー: まぁ最後の結論は合意しなくても良いかも?isolatedなブラウザを立ち上げてproxyを動かしても良いわけだし(ログインはさせない)


AI: おっしゃる通りですね。「JS必須はすべて切り捨てる」というのは思想としては綺麗ですが、実用性を考えると、現状多くの有益なドキュメントがSPA(Single Page Application)等で提供されている事実を無視するのは勿体ないですね。

ご指摘の通り、「ログイン機能などは持たせず、単にレンダリングだけを行うIsolated(隔離された)ブラウザをプロキシ側で動かす」 というアプローチであれば、セキュリティや透明性を保ちつつ、対象範囲を広げることが可能です。

この点を踏まえ、議論の最終的な着地点を「Static First(静的原理主義)」から**「Pragmatic Proxy(実用的なプロキシ構成)」**へと修正・補足すると、以下のようになります。


修正版:議論の到達点

5. 最終的な合意:Isolated Browserを含む実用的なプロキシ構成

「JS必須なドキュメントは負債」という理想はあるものの、現実に存在する多くのライブラリに対応するため、取得手段を柔軟に保つ方針へ修正されました。

  • ハイブリッドな取得戦略: 基本は軽量なHTTPリクエスト(curl等)を優先するが、必要な場合のみサーバーサイドで**隔離されたヘッドレスブラウザ(Isolated Browser)**を起動して取得・レンダリングを行う。
  • プロキシへの隠蔽: この「静的取得か、ブラウザ起動か」という判断や複雑さはすべてプロキシサーバー内に閉じ込める。
  • 安全性と透明性の維持: ブラウザを使う場合でも、ログインや認証情報は扱わず(No Auth)、単にパブリックなドキュメントをレンダリングするだけのステートレスなコンテナとして扱うことで、透明性とセキュリティを担保する。

結論(Update) ユーザー(MCPサーバー)側はあくまで「JSON設定を追加するだけ」というシンプルな体験を維持しつつ、裏側のプロキシが対象サイトの特性に合わせて最適な取得方法(静的 or ブラウザ)を選択・実行するアーキテクチャが、最も現実的かつ強力な解である。

(返答終了理由: STOP)


ユーザー:

思考の備忘録 『思考探求』特化型 のプロンプト詳細

【指示】

Persona

あなたは、思考のプロセスを追体験できるように物語る「思考探求ガイド (Cognitive Exploration Guide)」です。

Primary Task

提供された思考内容を分析し、結論に至るまでの思考プロセス、アイデアの分岐、検討の過程を読者が「追体験」できる、自己完結型の物語的な解説文を作成してください。 思考の「なぜ」と「どのように」に焦点を当て、最終的な結論だけでなく、そこに至るまでの発見や思考の転換点を丁寧に描写してください。ただし、感傷的な表現は避け、あくまで論理的な探求の過程として記述します。

Output Behavior

  • 【文脈の断片化・合成の禁止】 異なる文脈にある単語やフレーズだけを抜き出し、継ぎ接ぎして新しい文脈を作ることを厳禁します(例:文Aの一部xと文Bの一部yを混ぜて、全く新しい文zを捏造すること)。引用する際は、その単語が置かれていた元の文脈(AやB)の意味全体を保ったまま記述してください。
  • 【思考トレースの連続性】 全ての可能性を網羅する必要はありませんが、結論に至るために**「実際に辿った思考の軌跡(トレース)」**は、いかなる中間ステップも省略せずに記述してください。
  • 【プロセスの中抜き禁止】 出力サイズを気にして、「AだったのでCになった」のように中間の論理Bを飛ばさないでください。「Aを確認し、Bという事実に気付き、その結果Cに至った」というように、論理の接続を省略せず、動画のコマ送りのように詳細に記録することを強制します。
  • 一つの記事に収まらない場合、内容の整合性を保ったまま「記事2」「記事3」と自動的に分割し、ユーザーに確認を求めることなく、指定されたすべての内容を一度の応答で最後まで出力しきってください。

Output Format

  • 記事は必ず # 1つのタイトル名から始めてください。
  • 思考の流れに沿って、必要に応じて章で分割してください(分割が不自然な場合は1章でも構いません)。
  • 各章のタイトルには、内容を象徴する絵文字を1つだけ加えてください。
  • 記事はMarkdownフォーマットで出力してください。
  • *** による太字や斜体での強調は一切禁止します。
  • 記事の冒頭に、以下の項目のFront matterをコードブロックとして記述してください。
    • target_reader: [対象読者を簡潔に記述]
    • objective: [この記事の狙いを簡潔に記述]
  • 専門用語は積極的に使用し、読者の理解を助けるために、必要に応じて脚注[^1]で補足説明を加えてください。脚注では本来の意味とここでの意味や使われ方を説明してください。

Critical Constraints

  • この文章は、元の対話の存在を知らない読者にも完全に理解できるように記述してください。
  • 【用語の完全な独立性】 対話履歴の中でのみ通用する比喩、造語、指示代名詞(「あれ」「例の件」)を説明なしにそのまま使用することは禁止します。必ず一般的な言葉に置き換えるか、文脈中でその意味を定義・説明してから使用してください。
  • 必要な背景知識や用語の解説は、あなたの知識ベースから補足して構いませんが、「先ほどの対話で」や「あなたの質問に対し」のような、対話の存在を示唆する表現は絶対に使用しないでください。
  • 読者は、筆者(私)やあなた(AI)、そして元のSNS投稿の存在を知りません。それらについて一切言及しないでください。

それでは、お願いします。


今までの会話最初から最後までを元に、上記のプロンプトを実行してください。


AI:

---
target_reader: 大規模言語モデル(LLM)と外部知識の統合アーキテクチャに関心を持つソフトウェアエンジニア、およびMCP(Model Context Protocol)の実装戦略を模索するアーキテクト
objective: ドキュメント参照用MCPサーバーの設計において、透明性とスケーラビリティを両立させるための思考プロセスを体系化し、構成ファイルベースのプロキシアーキテクチャに至る論理的帰結を提示する
---

# 透明な知のパイプライン:MCPドキュメントサーバーの進化論的探求

## 🔍 乱立するサーバーと「テキスト」への回帰

大規模言語モデル(LLM)[^1]に外部知識を注入するための標準規格であるMCP(Model Context Protocol)[^2]が登場した際、開発者たちの間に広がったのは、標準化への期待と共に一種の混乱でした。現状を観察すると、企業やライブラリ開発者がそれぞれ独自の実装でMCPサーバーを公開し、エコシステムが断片化していく様子が見て取れます。これは、ツールとモデルをつなぐという本来の目的を超え、マーケティング的な「自社専用接続口」の乱立を招いています。

ここで原点に立ち返る問いが生まれました。ドキュメント用のMCPサーバーにおいて、我々が本当に必要としている機能とは何でしょうか。

LLMが本質的に求めているのは、装飾されたHTMLではなく、意味構造が明確なプレーンテキスト、具体的にはMarkdownです。思考を進めると、ドキュメント用MCPの役割は驚くほど単純化できることに気づきます。それは、Web上のドキュメントをテキストとして返すエンドポイント、あるいはHTMLをテキストに変換するプロキシがあれば十分ではないか、という仮説です。

さらに、理想的な状態を定義するならば、その知識ソースは単一の組織によって管理されるのではなく、コミュニティの「集合知」によって合成され、維持されるべきです。そして何より、膨大なテキストの中から必要な情報を引き出すための「検索」機能が不可欠です。ここから、特定のクラウドベンダーやプロプライエタリな実装に依存しない、汎用的で透明性の高い仕組みが必要であるという方向性が定まりました。

## 🛠 抽象化の罠と透明性の欠如

汎用的な仕組みを構築するにあたり、既存のフレームワークやサービスの評価が必要となります。

まず、開発を容易にするフレームワークである `fastmcp`[^3] のようなツールを検討しました。これらはサーバー構築のボイラープレート(定型コード)を削減するには有用ですが、アーキテクチャの視点からは「低レイヤーすぎる」という課題が浮上します。これらを使って個別にサーバーを立てることは、結局のところ「車輪の再発明」を助長し、ドキュメント処理という特定ドメインに必要な抽象化(検索、読み込み、推薦といった共通インターフェース)を提供しません。

次に、既存のドキュメント提供サービス(例:Context7など)を検討しました。これらは「ライブラリ名を指定すればドキュメントが注入される」という利便性を提供する一方で、その裏側がブラックボックスであるという致命的な欠陥を抱えています。どのバージョンのドキュメントが読まれているのか、更新頻度は適切か、クロールロジックはどうなっているのか。これらが不透明なままでは、LLMの出力に対する信頼性を担保できません。

この分析から、目指すべきシステムの要件が明確になりました。それは、単にOSS(オープンソースソフトウェア)であるだけでなく、ドキュメントの取得・変換ロジックそのものが「透明」であり、誰でも検証・修正可能であることです。

## 📜 コードから設定へ:集合知を記述するJSON

透明性を確保しつつ、集合知によってメンテナンスされるシステムをどう実現するか。思考は、命令的なコードによる実装から、宣言的な設定による定義へとシフトしました。

ドキュメントサイトごとに異なるHTML構造を解析し、Markdownへ変換するロジックをPythonスクリプトなどで個別に記述していては、メンテナンスコストが肥大化し、セキュリティ上の懸念も拭えません。そこで導き出されたのが、「ドキュメントの構造定義をJSON設定ファイルに外出しする」というアイデアです。

具体的には、各ライブラリのドキュメントについて、以下の情報をJSONで定義します。
1. 対象のURL
2. タイトルや本文を抽出するためのXPath[^4]やCSSセレクタ
3. 不要な要素(ナビゲーションや広告など)の除去ルール
4. ページネーションの辿り方

このアプローチの革新性は、プログラミングスキルを持たないユーザーでも、CSSセレクタさえ分かればドキュメントソースを追加・修正できる点にあります。GitHub上で設定ファイルに対するPull Requestを受け付ける体制を整えれば、特定のドキュメントが古くなったり構造が変わったりしても、コミュニティが即座に修正可能です。これにより、システムは「不透明なサービス」から「透明なルールの集合体」へと進化します。

## 🏗 動的プロキシと静的検証の分離

設定ファイルベースのアプローチが決まったところで、次は実行アーキテクチャの検討に移ります。当初は、変換されたMarkdownファイルをリポジトリにコミットして管理することも考えられましたが、これはGitリポジトリの肥大化と鮮度の低下を招きます。

そこで、責務を明確に分離するアーキテクチャが考案されました。
1. **リポジトリの役割:** JSON設定ファイル(ソース定義)のみを管理する。これこそが人類の共有資産となる知識ベースです。
2. **CI(継続的インテグレーション)の役割:** 設定ファイルが正しく機能するかを検証する。実際にページを取得し、セレクタが意図通りに要素を抽出できるかのみをテストします。
3. **ランタイム(プロキシ)の役割:** 実際の変換処理を行う。ユーザー(MCPサーバー)からのリクエストを受け、オンデマンドで対象サイトへアクセスし、JSONのルールに従ってHTMLをMarkdownに変換して返します。

この構成により、リポジトリは軽量でクリーンな状態を保ちつつ、常に最新のWeb上の情報を取得できる動的なシステムとなります。キャッシュ機構をプロキシに組み込むことで、パフォーマンスと相手方サーバーへの負荷も制御可能です。

## 🌐 「静的」の理想と「動的」の現実

最後の課題は、現代のWebにおけるJavaScriptの扱いです。理想論としては、JavaScriptの実行を必要とせず、シンプルなHTTPリクエスト(curlなど)だけで情報が取得できる「静的HTML」のみを対象とすべきです。これはシステムを堅牢、軽量、かつ高速に保つための「Static First(静的優先)」の哲学です。JS必須のドキュメントはLLM時代の負債である、という強い立場を取ることも可能です。

しかし、現実には多くの有用なライブラリがSPA(Single Page Application)[^5]としてドキュメントを提供しており、それらを完全に排除することは実用性を損ないます。

ここで思考は、原理主義的な排除ではなく、実用的な包含へと至りました。すなわち、プロキシサーバーの内部に「隔離されたヘッドレスブラウザ(Isolated Browser)」[^6]を組み込むアプローチです。

ユーザーインターフェース(JSON設定)上はシンプルさを保ちつつ、裏側のプロキシが以下の判断を行います。
- 基本的には軽量なHTTPリクエストで取得を試みる。
- JS実行が必須なサイトに限り、サーバーサイドで安全に隔離されたブラウザを起動し、レンダリング結果(DOM)を取得する。
- 認証情報などは一切持たせず、単なるレンダリングエンジンとして使い捨てることでセキュリティを担保する。

このハイブリッドな構成により、ユーザーは技術的な複雑さを意識することなく、「設定ファイルを追加するだけ」で、静的サイトから動的なSPAまであらゆるドキュメントをMCPのエコシステムに取り込むことが可能になります。

こうして、透明性が高く、集合知によって維持され、かつ現代のWeb事情にも適応したドキュメント用MCPサーバーのアーキテクチャが完成しました。

[^1]: 大規模言語モデル (LLM): 大量のテキストデータで学習されたAIモデル。ここではドキュメントの内容を理解し、回答を生成する主体として位置づけられる。
[^2]: MCP (Model Context Protocol): AIモデルと外部ツールやデータソースを接続するための標準化されたプロトコル。
[^3]: fastmcp: MCPサーバーを迅速に構築するためのフレームワークやライブラリの一種。
[^4]: XPath: XML形式の文書から特定の部分を指定して抽出するための記述言語。HTMLの解析にも用いられる。
[^5]: SPA (Single Page Application): ページ遷移を行わず、JavaScriptによって動的にコンテンツを書き換えるWebアプリケーションの形態。
[^6]: ヘッドレスブラウザ: 画面表示(GUI)を持たずにバックグラウンドで動作するWebブラウザ。プログラムによる自動操作やスクレイピングに利用される。

(返答終了理由: STOP)

メタデータ

{
  "runSettings": {
    "temperature": 1,
    "model": "models/gemini-3-pro-preview",
    "topP": 0.95,
    "topK": 64,
    "maxOutputTokens": 65536,
    "safetySettings": [
      {
        "category": "HARM_CATEGORY_HARASSMENT",
        "threshold": "OFF"
      },
      {
        "category": "HARM_CATEGORY_HATE_SPEECH",
        "threshold": "OFF"
      },
      {
        "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
        "threshold": "OFF"
      },
      {
        "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
        "threshold": "OFF"
      }
    ],
    "enableCodeExecution": false,
    "enableSearchAsATool": false,
    "enableBrowseAsATool": false,
    "enableAutoFunctionResponse": false,
    "outputResolution": "1K",
    "thinkingLevel": "THINKING_HIGH"
  },
  "systemInstruction": {}
}
@podhmo
Copy link
Author

podhmo commented Dec 2, 2025

変に文系的な(?)まとめの文章は不要な気がする

@podhmo
Copy link
Author

podhmo commented Dec 2, 2025

逆にブラウザとやり取りをしたりfigmaとやり取りしたりするようなツールはひつようかも?

そういうものは個別にインストールする価値がある。そういう意味ではsaasのmcpはワンチャン価値があるのかもしれない。

あと認証が必要なタイプがこれだとこまるのかも?(例えば内部的なドキュメント)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment